@jakobkg/shapes-ts 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,7 +2,8 @@
2
2
 
3
3
  Toy library to create runtime safe types in TS.
4
4
 
5
- When describing the shape of your data in shapes-ts, you get the corresponding TS type and a validation utility for free!
5
+ When describing the shape of your data in shapes-ts, you get the corresponding
6
+ TS type and a validation utility for free!
6
7
 
7
8
  ```typescript
8
9
  const Role = Shapes.object({
@@ -47,6 +48,11 @@ for (const member of movieData.cast) {
47
48
  - string
48
49
  - number
49
50
  - boolean
51
+
52
+ ...and literals of these
53
+
54
+ ### Composite types
55
+
50
56
  - object
51
57
  - array
52
58
 
@@ -54,12 +60,14 @@ for (const member of movieData.cast) {
54
60
 
55
61
  - Nullable types (`T | null`)
56
62
  - Optional types (`T | undefined`)
57
- - Unions (`A & B`)
58
- - Intersections (`A | B`)
63
+ - Unions (`A | B`)
64
+ - Intersections (`A & B`)
59
65
 
60
66
  ## Predicates
61
67
 
62
- Shapes can have additional validation checks added to them. These do not affect the inferred type, but are still ran as part of a shape's `.check()` method to help enforce constraints that are not easily modeled using the type system.
68
+ Shapes can have additional validation checks added to them. These do not affect
69
+ the inferred type, but are still ran as part of a shape's `.check()` method to
70
+ help enforce constraints that are not easily modeled using the type system.
63
71
 
64
72
  ```typescript
65
73
  const Username = Shapes.string().where(
@@ -71,7 +79,9 @@ Username.check("jakob :)"); // true
71
79
  Username.check("CptAmericaFan207"); // false
72
80
  ```
73
81
 
74
- Predicates can be used with all types of shapes, and they may be combined both by stacking them on a single shape and by combining shapes that already have predicates on them.
82
+ Predicates can be used with all types of shapes, and they may be combined both
83
+ by stacking them on a single shape and by combining shapes that already have
84
+ predicates on them.
75
85
 
76
86
  ```typescript
77
87
  const Fizz = Shapes.number().where(
package/dist/shapes.d.ts CHANGED
@@ -1,15 +1,16 @@
1
1
  declare const Predicates: unique symbol;
2
- declare const Optional: unique symbol;
3
2
  declare const Properties: unique symbol;
4
3
  declare const AllowUnknownProperties: unique symbol;
5
4
  /**
6
5
  * Bridge to convert a Shape into a TS type.
7
6
  */
8
7
  export type Type<T> = T extends Shape<infer U> ? U : never;
9
- type ShapePredicate<T> = (x: T) => boolean;
8
+ type ShapePredicate<T> = {
9
+ predicate: (x: T) => boolean;
10
+ description: string | undefined;
11
+ };
10
12
  interface Shape<T> {
11
13
  readonly typename: string;
12
- readonly [Optional]?: boolean;
13
14
  readonly [Predicates]: ShapePredicate<T>[];
14
15
  check(x: unknown): x is T;
15
16
  /**
@@ -18,9 +19,9 @@ interface Shape<T> {
18
19
  * @param description Optional description of the constraint for error messages
19
20
  * @returns A new shape with the additional validation
20
21
  */
21
- where(predicate: ShapePredicate<T>, description: string): Shape<T>;
22
- and<U>(other: Shape<U>): IntersectionShape<T, U>;
23
- or<U>(other: Shape<U>): UnionShape<T, U>;
22
+ where(predicate: (x: T) => boolean, description: string | undefined): Shape<T>;
23
+ and<U>(other: Shape<U>): Shape<T & U>;
24
+ or<U>(other: Shape<U>): Shape<T | U>;
24
25
  }
25
26
  interface ObjectShape<T = Record<string, unknown>> extends Shape<T> {
26
27
  readonly [Properties]: Record<string, Shape<T>>;
@@ -30,23 +31,6 @@ interface ObjectShapeOptions {
30
31
  readonly allowUnknownProperties?: boolean;
31
32
  readonly additionalPermittedProperties?: Record<string, Shape<Record<string, unknown>>>;
32
33
  }
33
- interface ArrayShape<T> extends Shape<Array<T>> {
34
- readonly inner: Shape<T>;
35
- }
36
- interface UnionShape<Left, Right> extends Shape<Left | Right> {
37
- left: Shape<Left>;
38
- right: Shape<Right>;
39
- }
40
- interface IntersectionShape<Left, Right> extends Shape<Left & Right> {
41
- left: Shape<Left>;
42
- right: Shape<Right>;
43
- }
44
- interface OptionalShape<T> extends Shape<T | undefined> {
45
- readonly inner: Shape<T>;
46
- }
47
- interface NullableShape<T> extends Shape<T | null> {
48
- readonly inner: Shape<T>;
49
- }
50
34
  /**
51
35
  * Creates a shape representing a JS `number`.
52
36
  * Does not support BigInt.
@@ -60,13 +44,13 @@ export declare function string(): Shape<string>;
60
44
  * Creates a shape representing a JS `boolean`.
61
45
  */
62
46
  export declare function boolean(): Shape<boolean>;
63
- type Primitive = number | string | boolean | object | null | undefined;
64
- export declare function literal<X extends Primitive, T extends Primitive extends X ? never : X>(x: X): Shape<T>;
47
+ type Primitive = number | string | boolean | null | undefined;
48
+ export declare function literal<T extends Primitive>(x: T): Shape<T>;
65
49
  /**
66
50
  * Creates an array shape, representing `Array<T>` (aka `T[]`).
67
51
  * Takes the shape representing `T` as a parameter.
68
52
  */
69
- export declare function array<T>(shape: Shape<T>): ArrayShape<T>;
53
+ export declare function array<T>(shape: Shape<T>): Shape<T[]>;
70
54
  /**
71
55
  * Creates an object shape.
72
56
  *
@@ -89,15 +73,19 @@ export declare function array<T>(shape: Shape<T>): ArrayShape<T>;
89
73
  export declare function object<T extends Record<string, Shape<any>>>(properties: T, options?: ObjectShapeOptions): ObjectShape<{
90
74
  [K in keyof T]: Type<T[K]>;
91
75
  }>;
76
+ export declare function tuple<Shapes extends Shape<any>[], Partial extends {
77
+ [K in keyof Shapes]: Type<Shapes[K]>;
78
+ }, Tuple extends RestShape extends Shape<infer Rest> ? [...Partial, ...Rest[]] : [...Partial], RestShape extends Shape<any> | undefined = undefined>(shapes: [...Shapes], rest?: RestShape): Shape<Tuple>;
79
+ export { enumOf as enum };
80
+ declare function enumOf<T extends (string | number)[]>(...values: T): Shape<T[number]>;
92
81
  /**
93
82
  * Creates a shape representing an optional type.
94
83
  * `Shapes.optional(T)` corresponds to `T | undefined`
95
84
  */
96
- export declare function optional<T>(shape: Shape<T>): OptionalShape<T>;
85
+ export declare function optional<T>(shape: Shape<T>): Shape<T | undefined>;
97
86
  /**
98
87
  * Creates a shape representing a nullable type.
99
88
  * `Shapes.nullable(T)` corresponds to `T | null`
100
89
  */
101
- export declare function nullable<T>(shape: Shape<T>): NullableShape<T>;
102
- export {};
90
+ export declare function nullable<T>(shape: Shape<T>): Shape<T | null>;
103
91
  //# sourceMappingURL=shapes.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"shapes.d.ts","sourceRoot":"","sources":["../src/shapes/shapes.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"shapes.d.ts","sourceRoot":"","sources":["../src/shapes/shapes.ts"],"names":[],"mappings":"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"}
package/dist/shapes.js CHANGED
@@ -26,12 +26,13 @@ exports.boolean = boolean;
26
26
  exports.literal = literal;
27
27
  exports.array = array;
28
28
  exports.object = object;
29
+ exports.tuple = tuple;
30
+ exports.enum = enumOf;
29
31
  exports.optional = optional;
30
32
  exports.nullable = nullable;
31
33
  /// SYMBOLS
32
34
  // These are here to hide some API bits from consumers
33
35
  var Predicates = Symbol();
34
- var Optional = Symbol();
35
36
  var Properties = Symbol();
36
37
  var AllowUnknownProperties = Symbol();
37
38
  /// TYPE GUARDS
@@ -49,9 +50,6 @@ function isObject(input) {
49
50
  function isArray(input) {
50
51
  return Array.isArray(input);
51
52
  }
52
- function isNull(input) {
53
- return input === null;
54
- }
55
53
  function isBoolean(input) {
56
54
  return typeof input === "boolean";
57
55
  }
@@ -61,17 +59,16 @@ function isUndefined(input) {
61
59
  function makeUnion(left, right) {
62
60
  var _a;
63
61
  return _a = {
64
- typename: "".concat(left.typename, " | ").concat(right.typename),
65
- left: left,
66
- right: right
62
+ typename: "".concat(left.typename, " | ").concat(right.typename)
67
63
  },
68
64
  _a[Predicates] = [],
69
- _a.where = function (predicate) {
70
- return __assign(__assign({}, this), { predicates: __spreadArray(__spreadArray([], this[Predicates], true), [predicate], false) });
65
+ _a.where = function (predicate, description) {
66
+ var _a;
67
+ return __assign(__assign({}, this), (_a = {}, _a[Predicates] = __spreadArray(__spreadArray([], this[Predicates], true), [{ predicate: predicate, description: description }], false), _a));
71
68
  },
72
69
  _a.check = function (x) {
73
70
  return (left.check(x) || right.check(x)) &&
74
- this[Predicates].every(function (p) { return p(x); });
71
+ this[Predicates].every(function (p) { return p.predicate(x); });
75
72
  },
76
73
  _a.and = function (other) {
77
74
  return makeIntersection(this, other);
@@ -82,20 +79,22 @@ function makeUnion(left, right) {
82
79
  _a;
83
80
  }
84
81
  function makeIntersection(left, right) {
85
- var _a, _b, _c;
82
+ var _a;
86
83
  return _a = {
87
- typename: "".concat(left.typename, " | ").concat(right.typename),
88
- left: __assign(__assign({}, left), (_b = {}, _b[Properties] = __assign(__assign({}, right[Properties]), left[Properties]), _b)),
89
- right: __assign(__assign({}, right), (_c = {}, _c[Properties] = __assign(__assign({}, left[Properties]), right[Properties]), _c))
84
+ typename: "".concat(left.typename, " & ").concat(right.typename)
90
85
  },
91
86
  _a[Predicates] = [],
92
- _a.where = function (predicate) {
87
+ _a.where = function (predicate, description) {
93
88
  var _a;
94
- return __assign(__assign({}, this), (_a = {}, _a[Predicates] = __spreadArray(__spreadArray([], this[Predicates], true), [predicate], false), _a));
89
+ return __assign(__assign({}, this), (_a = {}, _a[Predicates] = __spreadArray(__spreadArray([], this[Predicates], true), [{ predicate: predicate, description: description }], false), _a));
95
90
  },
96
91
  _a.check = function (x) {
97
- return this.left.check(x) && this.right.check(x) &&
98
- this[Predicates].every(function (p) { return p(x); });
92
+ var _a, _b;
93
+ // Trickery: combine permitted properties of left and right
94
+ var tolerantLeft = __assign(__assign({}, left), (_a = {}, _a[Properties] = __assign(__assign({}, right[Properties]), left[Properties]), _a));
95
+ var tolerantRight = __assign(__assign({}, right), (_b = {}, _b[Properties] = __assign(__assign({}, left[Properties]), right[Properties]), _b));
96
+ return tolerantLeft.check(x) && tolerantRight.check(x) &&
97
+ this[Predicates].every(function (p) { return p.predicate(x); });
99
98
  },
100
99
  _a.and = function (other) {
101
100
  return makeIntersection(this, other);
@@ -117,11 +116,11 @@ function number() {
117
116
  },
118
117
  _a[Predicates] = [],
119
118
  _a.check = function (x) {
120
- return isNumber(x) && this[Predicates].every(function (p) { return p(x); });
119
+ return isNumber(x) && this[Predicates].every(function (p) { return p.predicate(x); });
121
120
  },
122
- _a.where = function (predicate) {
121
+ _a.where = function (predicate, description) {
123
122
  var _a;
124
- return __assign(__assign({}, this), (_a = {}, _a[Predicates] = __spreadArray(__spreadArray([], this[Predicates], true), [predicate], false), _a));
123
+ return __assign(__assign({}, this), (_a = {}, _a[Predicates] = __spreadArray(__spreadArray([], this[Predicates], true), [{ predicate: predicate, description: description }], false), _a));
125
124
  },
126
125
  _a.and = function (other) {
127
126
  return makeIntersection(this, other);
@@ -139,13 +138,13 @@ function string() {
139
138
  return _a = {
140
139
  typename: "string",
141
140
  check: function (x) {
142
- return isString(x) && this[Predicates].every(function (p) { return p(x); });
141
+ return isString(x) && this[Predicates].every(function (p) { return p.predicate(x); });
143
142
  }
144
143
  },
145
144
  _a[Predicates] = [],
146
- _a.where = function (predicate) {
145
+ _a.where = function (predicate, description) {
147
146
  var _a;
148
- return __assign(__assign({}, this), (_a = {}, _a[Predicates] = __spreadArray(__spreadArray([], this[Predicates], true), [predicate], false), _a));
147
+ return __assign(__assign({}, this), (_a = {}, _a[Predicates] = __spreadArray(__spreadArray([], this[Predicates], true), [{ predicate: predicate, description: description }], false), _a));
149
148
  },
150
149
  _a.and = function (other) {
151
150
  return makeIntersection(this, other);
@@ -163,13 +162,13 @@ function boolean() {
163
162
  return _a = {
164
163
  typename: "boolean",
165
164
  check: function (x) {
166
- return isBoolean(x) && this[Predicates].every(function (p) { return p(x); });
165
+ return isBoolean(x) && this[Predicates].every(function (p) { return p.predicate(x); });
167
166
  }
168
167
  },
169
168
  _a[Predicates] = [],
170
- _a.where = function (predicate) {
169
+ _a.where = function (predicate, description) {
171
170
  var _a;
172
- return __assign(__assign({}, this), (_a = {}, _a[Predicates] = __spreadArray(__spreadArray([], this[Predicates], true), [predicate], false), _a));
171
+ return __assign(__assign({}, this), (_a = {}, _a[Predicates] = __spreadArray(__spreadArray([], this[Predicates], true), [{ predicate: predicate, description: description }], false), _a));
173
172
  },
174
173
  _a.and = function (other) {
175
174
  return makeIntersection(this, other);
@@ -181,16 +180,20 @@ function boolean() {
181
180
  }
182
181
  function literal(x) {
183
182
  var _a;
183
+ function matchesLiteral(u) {
184
+ return u === x;
185
+ }
184
186
  return _a = {
185
- typename: JSON.stringify(x)
187
+ typename: isUndefined(x) ? "undefined" : JSON.stringify(x)
186
188
  },
187
189
  _a[Predicates] = [],
188
190
  _a.check = function (input) {
189
- return input === x && this[Predicates].every(function (p) { return p(input); });
191
+ return matchesLiteral(input) &&
192
+ this[Predicates].every(function (p) { return p.predicate(input); });
190
193
  },
191
- _a.where = function (predicate) {
194
+ _a.where = function (predicate, description) {
192
195
  var _a;
193
- return __assign(__assign({}, this), (_a = {}, _a[Predicates] = __spreadArray(__spreadArray([], this[Predicates], true), [predicate], false), _a));
196
+ return __assign(__assign({}, this), (_a = {}, _a[Predicates] = __spreadArray(__spreadArray([], this[Predicates], true), [{ predicate: predicate, description: description }], false), _a));
194
197
  },
195
198
  _a.and = function (other) {
196
199
  return makeIntersection(this, other);
@@ -210,23 +213,18 @@ function array(shape) {
210
213
  var typename = "Array<".concat(shape.typename, ">");
211
214
  return _a = {
212
215
  typename: typename,
213
- inner: shape,
214
216
  check: function (input) {
215
- if (!isArray(input)) {
216
- return false;
217
+ function innerMatches(x) {
218
+ return x.every(function (entry) { return shape.check(entry); });
217
219
  }
218
- return input.every(function (entry) {
219
- if (!shape.check(entry)) {
220
- return false;
221
- }
222
- return true;
223
- }) && this[Predicates].every(function (p) { return p(input); });
220
+ return isArray(input) && innerMatches(input) &&
221
+ this[Predicates].every(function (p) { return p.predicate(input); });
224
222
  }
225
223
  },
226
224
  _a[Predicates] = [],
227
- _a.where = function (predicate) {
225
+ _a.where = function (predicate, description) {
228
226
  var _a;
229
- return __assign(__assign({}, this), (_a = {}, _a[Predicates] = __spreadArray(__spreadArray([], this[Predicates], true), [predicate], false), _a));
227
+ return __assign(__assign({}, this), (_a = {}, _a[Predicates] = __spreadArray(__spreadArray([], this[Predicates], true), [{ predicate: predicate, description: description }], false), _a));
230
228
  },
231
229
  _a.and = function (other) {
232
230
  return makeIntersection(this, other);
@@ -258,44 +256,52 @@ function array(shape) {
258
256
  // deno-lint-ignore no-explicit-any
259
257
  function object(properties, options) {
260
258
  var _a;
261
- var allowUnknownProperties = options === null || options === void 0 ? void 0 : options.allowUnknownProperties;
259
+ var _b;
260
+ var allowUnknownProperties = (_b = options === null || options === void 0 ? void 0 : options.allowUnknownProperties) !== null && _b !== void 0 ? _b : false;
262
261
  return _a = {
263
262
  typename: "Object"
264
263
  },
265
264
  _a[AllowUnknownProperties] = allowUnknownProperties,
266
265
  _a.check = function (input) {
267
- // Check that input is an object
268
- if (!isObject(input)) {
269
- return false;
270
- }
271
- // Check for unknown properties
272
- if (!this[AllowUnknownProperties]) {
273
- for (var inputProperty in input) {
274
- if (!(inputProperty in this[Properties])) {
275
- return false;
276
- }
277
- }
278
- }
279
- // Check required properties and their types
280
- for (var property in this[Properties]) {
281
- var field = input[property];
282
- var propertyShape = this[Properties][property];
283
- // Property presence check
284
- if (!(property in input) && !propertyShape[Optional]) {
266
+ var _this = this;
267
+ var matchesShape = function (input) {
268
+ // Check that input is an object
269
+ if (!isObject(input)) {
285
270
  return false;
286
271
  }
287
- // Property type check
288
- if (!propertyShape.check(field)) {
289
- return false;
272
+ // Check for unknown properties
273
+ if (!_this[AllowUnknownProperties]) {
274
+ for (var inputProperty in input) {
275
+ if (!(inputProperty in _this[Properties])) {
276
+ return false;
277
+ }
278
+ }
290
279
  }
291
- }
292
- return this[Predicates].every(function (p) { return p(input); });
280
+ // Check required properties and their types
281
+ for (var property in _this[Properties]) {
282
+ var field = input[property];
283
+ var propertyShape = _this[Properties][property];
284
+ if (isUndefined(propertyShape))
285
+ return false;
286
+ // Property presence check
287
+ if (!(property in input) && !propertyShape.check(undefined)) {
288
+ return false;
289
+ }
290
+ // Property type check
291
+ if (!propertyShape.check(field)) {
292
+ return false;
293
+ }
294
+ }
295
+ return true;
296
+ };
297
+ return matchesShape(input) &&
298
+ this[Predicates].every(function (p) { return p.predicate(input); });
293
299
  },
294
300
  _a[Properties] = __assign(__assign({}, properties), options === null || options === void 0 ? void 0 : options.additionalPermittedProperties),
295
301
  _a[Predicates] = [],
296
- _a.where = function (predicate) {
302
+ _a.where = function (predicate, description) {
297
303
  var _a;
298
- return __assign(__assign({}, this), (_a = {}, _a[Predicates] = __spreadArray(__spreadArray([], this[Predicates], true), [predicate], false), _a));
304
+ return __assign(__assign({}, this), (_a = {}, _a[Predicates] = __spreadArray(__spreadArray([], this[Predicates], true), [{ predicate: predicate, description: description }], false), _a));
299
305
  },
300
306
  _a.and = function (other) {
301
307
  return makeIntersection(this, other);
@@ -305,26 +311,29 @@ function object(properties, options) {
305
311
  },
306
312
  _a;
307
313
  }
308
- /// TYPE MODIFIERS
309
- /**
310
- * Creates a shape representing an optional type.
311
- * `Shapes.optional(T)` corresponds to `T | undefined`
312
- */
313
- function optional(shape) {
314
+ function tuple(shapes, rest) {
314
315
  var _a;
316
+ var typename = "[".concat(shapes.map(function (s) { return s.typename; }).join(", "), "]");
315
317
  return _a = {
316
- typename: "".concat(shape.typename, " | undefined"),
317
- inner: shape
318
+ typename: typename
318
319
  },
319
- _a[Optional] = true,
320
320
  _a[Predicates] = [],
321
- _a.check = function (input) {
322
- return (isUndefined(input) || shape.check(input)) &&
323
- this[Predicates].every(function (p) { return p(input); });
321
+ _a.check = function (x) {
322
+ if (!isArray(x))
323
+ return false;
324
+ var xMightHaveRest = x.length > shapes.length;
325
+ var haveRestShape = rest !== undefined;
326
+ if (haveRestShape && xMightHaveRest) {
327
+ for (var idx = shapes.length; idx < x.length; idx++) {
328
+ if (!rest.check(x[idx]))
329
+ return false;
330
+ }
331
+ }
332
+ return shapes.every(function (shape, idx) { return shape.check(x[idx]); });
324
333
  },
325
- _a.where = function (predicate) {
334
+ _a.where = function (predicate, description) {
326
335
  var _a;
327
- return __assign(__assign({}, this), (_a = {}, _a[Predicates] = __spreadArray(__spreadArray([], this[Predicates], true), [predicate], false), _a));
336
+ return __assign(__assign({}, this), (_a = {}, _a[Predicates] = __spreadArray(__spreadArray([], this[Predicates], true), [{ predicate: predicate, description: description }], false), _a));
328
337
  },
329
338
  _a.and = function (other) {
330
339
  return makeIntersection(this, other);
@@ -334,24 +343,22 @@ function optional(shape) {
334
343
  },
335
344
  _a;
336
345
  }
337
- /**
338
- * Creates a shape representing a nullable type.
339
- * `Shapes.nullable(T)` corresponds to `T | null`
340
- */
341
- function nullable(shape) {
346
+ function enumOf() {
342
347
  var _a;
343
- var nullShape = (_a = {
344
- typename: "".concat(shape.typename, " | null"),
345
- check: function (input) {
346
- return (isNull(input) || shape.check(input)) &&
347
- this[Predicates].every(function (p) { return p(input); });
348
- },
349
- inner: shape
348
+ var values = [];
349
+ for (var _i = 0; _i < arguments.length; _i++) {
350
+ values[_i] = arguments[_i];
351
+ }
352
+ return _a = {
353
+ typename: "".concat(values.map(function (v) { return JSON.stringify(v); }).join(" | "))
350
354
  },
351
355
  _a[Predicates] = [],
352
- _a.where = function (predicate) {
356
+ _a.check = function (x) {
357
+ return (isNumber(x) || isString(x)) && values.includes(x);
358
+ },
359
+ _a.where = function (predicate, description) {
353
360
  var _a;
354
- return __assign(__assign({}, this), (_a = {}, _a[Predicates] = __spreadArray(__spreadArray([], this[Predicates], true), [predicate], false), _a));
361
+ return __assign(__assign({}, this), (_a = {}, _a[Predicates] = __spreadArray(__spreadArray([], this[Predicates], true), [{ predicate: predicate, description: description }], false), _a));
355
362
  },
356
363
  _a.and = function (other) {
357
364
  return makeIntersection(this, other);
@@ -359,6 +366,20 @@ function nullable(shape) {
359
366
  _a.or = function (other) {
360
367
  return makeUnion(this, other);
361
368
  },
362
- _a);
363
- return nullShape;
369
+ _a;
370
+ }
371
+ /// TYPE MODIFIERS
372
+ /**
373
+ * Creates a shape representing an optional type.
374
+ * `Shapes.optional(T)` corresponds to `T | undefined`
375
+ */
376
+ function optional(shape) {
377
+ return makeUnion(shape, literal(undefined));
378
+ }
379
+ /**
380
+ * Creates a shape representing a nullable type.
381
+ * `Shapes.nullable(T)` corresponds to `T | null`
382
+ */
383
+ function nullable(shape) {
384
+ return makeUnion(shape, literal(null));
364
385
  }
package/package.json CHANGED
@@ -6,7 +6,7 @@
6
6
  },
7
7
  "homepage": "https://codeberg.org/jakobkg/shapes-ts#readme",
8
8
  "license": "BSD-3-Clause",
9
- "version": "0.2.0",
9
+ "version": "0.3.0",
10
10
  "private": false,
11
11
  "main": "dist/index.js",
12
12
  "scripts": {