0.4.0 • Published 2 years ago

@renke/vod v0.4.0

Weekly downloads
-
License
ISC
Repository
-
Last release
2 years ago

vod

Immutable, type-safe, validated, nominal value objects in TypeScript based on @renke/vo and zod.

Installation

npm install @renke/vod

If you don't have zod installed already:

npm install @renke/vod zod

Usage

Simple Value Objects (for primitive types)

import { z } from "zod";
import { v } from "@renke/vod";

const PositiveNumber = v("PositiveNumber", z.number().min(1));

type PositiveNumber = z.infer<typeof PositiveNumber>;

// OKAY
const number1: PositiveNumber = PositiveNumber.create(1);

// NOT OKAY - Fails at run time because -1 is not a positive number
const number2: PositiveNumber = PositiveNumber.create(-1);

const number3: PositiveNumber = PositiveNumber.create(1);

// OKAY – PositiveNumber is a number
const number4: number = number3 + 1;

// NOT OKAY – The result might not be a positive number
const number5: PositiveNumber = number3 - 2;

// NOT OKAY - Fails at run time because -1 is not a positive number
const number6: PositiveNumber = PositiveNumber.create(number3 - 2);

// NOT OKAY – number might not be a positive number
const number7: PositiveNumber = -1;

const add = (x: PositiveNumber, y: PositiveNumber): PositiveNumber => {
  return PositiveNumber.create(x + y);
};

// NOT OKAY – number4 might not be a positive number
const number8 = add(number3, number4);

// OKAY
const number9: PositiveNumber = add(number1, number3);

const number10: unknown = 1;

// NOT OKAY – number10 is not a number (or PositiveNumber)
PositiveNumber.create(number10);

// OKAY – parse from zod allows unknown types
PositiveNumber.parse(number10);

const NegativeNumber = v("NegativeNumber", z.number().max(0));

type NegativeNumber = z.infer<typeof NegativeNumber>;

// OKAY
const number11 = NegativeNumber.create(-1);

// NOT OKAY – number11 is not a PositiveNumber
const number12: PositiveNumber = number11;

Complex Value Objects

import { z } from "zod";
import { v } from "@renke/vod";

const User = v(
  "User",
  z.object({ first: z.string().min(1), last: z.string().min(1) })
);

type User = z.infer<typeof User>;

// NOT OKAY – Object might not be a valid User
const user1: User = { first: "John", last: "Doe" };

// OKAY
const user2: User = User.create({ first: "John", last: "Doe" });

// NOT OKAY – User objects are not mutable
user2.first = "Jane";

// OKAY
const user3: User = User.create({ ...user2, first: "Jane" });

const Age = v("Age", z.number().min(0));

type Age = z.infer<typeof Age>;

const Profile = v("Profile", z.object({ age: Age, nick: z.string().min(1) }));

type Profile = z.infer<typeof Profile>;

const UserWithProfile = v(
  "UserProfile",
  z.object({
    first: z.string().min(1),
    last: z.string().min(1),
    profile: Profile,
  })
);

type UserWithProfile = z.infer<typeof UserWithProfile>;

// OKAY
const userWithProfile1 = UserWithProfile.create({
  first: "John",
  last: "Doe",
  profile: {
    age: 18,
    nick: "j18",
  },
});

// OKAY
const profile1 = Profile.create({ age: 18, nick: "j18" });

// OKAY
const userWithProfile2 = UserWithProfile.create({
  first: "John",
  last: "Doe",
  profile: profile1,
});

const replaceProfile = (
  user: UserWithProfile,
  profile: Profile
): UserWithProfile => {
  return UserWithProfile.create({ ...user, profile });
};

// OKAY
const profile2 = Profile.create({ age: 19, nick: "j19" });

// OKAY
const userWithProfile3 = replaceProfile(userWithProfile2, profile1);

// NOT OKAY – Object might not be a valid UserWithProfile
const userWithProfile4: UserWithProfile = { ...userWithProfile3, last: "Jane" };
0.3.0

2 years ago

0.4.0

2 years ago

0.1.0

2 years ago

0.2.0

2 years ago

0.0.2

3 years ago

0.0.1

3 years ago

0.0.0

3 years ago