ow icon indicating copy to clipboard operation
ow copied to clipboard

Composition

Open ziflex opened this issue 3 years ago • 3 comments

Hi guys, thanks for this amazing library!

I wonder if there is a way how to extend predicates or compose a new one using a set of others. Here is a use case:

interface User {
    id: string;
    email: string;
}

const assertUser = ow.create('User', ow.object.partialShape({
    id: ow.string.nonEmpty,
    email: ow.string.nonEmpty,
}))

interface Person extends User {
    firstName: string;
    lastName: string;
}

const assertPerson = ow.create('Person', ow.object.partialShape({
    id: ow.string.nonEmpty,
    email: ow.string.nonEmpty,
    firstName: ow.string.nonEmpty,
    lastName: ow.string.nonEmpty,
}))

I would love to be able to avoid code duplication.

ziflex avatar Feb 22 '22 16:02 ziflex

It might be possible, but it's not an easy task, especially because of TypeScript.

sindresorhus avatar Feb 22 '22 17:02 sindresorhus

I think the easiest path for reuse is this:

interface User {
    id: string;
    email: string;
}

const owUser = {
    id: ow.string.nonEmpty,
    email: ow.string.nonEmpty,
};

const assertUser = ow.create('User', ow.object.partialShape(owUser))

interface Person extends User {
    firstName: string;
    lastName: string;
}

const assertPerson = ow.create('Person', ow.object.partialShape({
    ...owUser,
    firstName: ow.string.nonEmpty,
    lastName: ow.string.nonEmpty,
}))

sindresorhus avatar Feb 22 '22 17:02 sindresorhus

That's what I ended up doing, but it's rather hacky and breaks an abstraction.

The easiest way of supporting this is to add a method something like ow.compose(name: string, ...validation: ReusableValidator<any>[]). But it creates 2 problems:

  • TypeScript unfriendliness
  • Error messages will point to different objects

ziflex avatar Feb 22 '22 18:02 ziflex