GithubHelp home page GithubHelp logo

Object shape validator about ow HOT 20 CLOSED

sindresorhus avatar sindresorhus commented on May 19, 2024
Object shape validator

from ow.

Comments (20)

sindresorhus avatar sindresorhus commented on May 19, 2024 3

I think it should be in core. I very often have APIs with an options-object and I want to quickly validate the options. Having to do separate ow calls for each property would be verbose and annoying.


I think this:

ow(target, ow.object.label('target').shape({
	width: ow.number.positive.integer,
	height: ow.number.positive.integer,
	data: ow.any(ow.uint8Array, ow.uint8ClampedArray)
}))

is better than this:

ow(target, ow.object.label('target'))
ow(target.width, ow.number.positive.integer.label('target.width'))
ow(target.height, ow.number.positive.integer.label('target.height'))
ow(target.data, ow.any(ow.uint8Array, ow.uint8ClampedArray))

We also wouldn't need label() for the object properties as they can be inferred.

from ow.

sindresorhus avatar sindresorhus commented on May 19, 2024 2

Or exactShape?

👍


When you only see .shape() in some code, is it clear enough that it allows additional properties? For me, it's not. How about partialShape() or looseShape()? I prefer the former. Open to other naming suggestions.

from ow.

transitive-bullshit avatar transitive-bullshit commented on May 19, 2024 1

I agree that this would be useful, though I'm not sure I'm in favor of adding it to the core API since unlike its usage in PropTypes, you can accomplish the same thing with multiple ow statements.

ow(input, ow.object)
ow(input.color, ow.string)
ow(input.height, ow.number.greatherThan(10))

This isn't possible with PropTypes which is one reason they added PropTypes.shape.

My main argument against it would be to keep the API surface as small as possible, but I do find myself using this pattern quite often especially for validating configuration parameters opts.

Take this concrete example where I'm using ow for this purpose. It'd be really awkward if I tried to use a combination of ow.object.shape and the upcoming optional predicate to achieve what is more clearly defined by multiple ow statements.

I could go either way, though, since I'm sure there are use cases where it'll still be useful to peeps. Just my 2 cents 👍

from ow.

sindresorhus avatar sindresorhus commented on May 19, 2024 1

PropTypes.shape() doesn't throw on additional unspecified keys. They have PropTypes.exact() for that. We need to handle both cases.

from ow.

sindresorhus avatar sindresorhus commented on May 19, 2024 1

Exact should mean "exact" in that the shape should have all the same properties as the input object.

from ow.

sindresorhus avatar sindresorhus commented on May 19, 2024 1

Should both of these checks fail

Yes

from ow.

transitive-bullshit avatar transitive-bullshit commented on May 19, 2024

We also wouldn't need label() for the object properties as they can be inferred.

💯

Sounds good to me :)

from ow.

SamVerschueren avatar SamVerschueren commented on May 19, 2024

We discussed this somewhere else, can't find it though. I believe our initial suggestion was just

ow(target, {
	width: ow.number.positive.integer,
	height: ow.number.positive.integer,
	data: ow.any(ow.uint8Array, ow.uint8ClampedArray)
})

So just passing an object as second parameter would do the trick. I see positive sides to both ideas.

from ow.

sindresorhus avatar sindresorhus commented on May 19, 2024

@SamVerschueren I like that shorthand, but there's no way to use a label or to make it optional (when that is added) with that...

from ow.

transitive-bullshit avatar transitive-bullshit commented on May 19, 2024

Just a note; the shape vs exact semantics seem very related to the optional operator and may have some overlap in implementation.

from ow.

sindresorhus avatar sindresorhus commented on May 19, 2024

@transitive-bullshit The optional operator would only be useful for known optional properties. What about unknown properties?

from ow.

IssueHuntBot avatar IssueHuntBot commented on May 19, 2024

@issuehuntfest has funded $60.00 to this issue. See it on IssueHunt

from ow.

mhaagens avatar mhaagens commented on May 19, 2024

Using this for simple input validation, unfortunately only throws on the first error, but that's all I need to make sure there are no erroneous inputs being passed.

const matchShape = (source, shape) =>
  new Promise((resolve, reject) => {
    for (let key of Object.keys(source)) {
      try {
        ow(source[key], shape[key]);
      } catch (e) {
        return reject(e);
      }
    }
    resolve();
});

Usage:

const obj = {
  id: "Gozxoqqy79"
}

await matchShape(obj, {
  id: ow.string
}).catch(e => {
  console.log(e);
});

from ow.

transitive-bullshit avatar transitive-bullshit commented on May 19, 2024

This is a nice wrapper @mhaagens 😄 Any reason it has to be asynchronous?

from ow.

mhaagens avatar mhaagens commented on May 19, 2024

Thanks! :) Doesn't have to be at all. Just like to be explicit about returning a promise when using async/await and I like the syntax better than callbacks :).

from ow.

transitive-bullshit avatar transitive-bullshit commented on May 19, 2024

@mhaagens I meant that there's no need to use async / Promise or callbacks in this case since everything's synchronous.

const matchShape = (source, shape) => {
  for (const key of Object.keys(source)) {
    ow(source[key], shape[key]);
  }
}

matchShape(obj, { id: ow.string })

from ow.

mhaagens avatar mhaagens commented on May 19, 2024

@transitive-bullshit Ah, yeah you're right!

from ow.

SamVerschueren avatar SamVerschueren commented on May 19, 2024

I want to start working on this. But before I do, what API are we going to use now?

// Allows extra properties
ow(target, ow.object.shape({
	width: ow.number.positive.integer,
	height: ow.number.positive.integer,
	data: ow.any(ow.uint8Array, ow.uint8ClampedArray)
}));

And

// Doesn't allow extra properties
ow(target, ow.object.exact({
	width: ow.number.positive.integer,
	height: ow.number.positive.integer,
	data: ow.any(ow.uint8Array, ow.uint8ClampedArray)
}));

Or exactShape?

from ow.

SamVerschueren avatar SamVerschueren commented on May 19, 2024

The partialShape is already done 👌. When I started on exactShape, I wasn't sure how it should handle certain use cases.

Does exactShape mean it should be exact in both directions?

ow({unicorn: '🦄'}, ow.object.exactShape({
	unicorn: ow.string,
	rainbow: ow.string
}));
ow({unicorn: '🦄', rainbow: '🌈'}, ow.object.exactShape({
	unicorn: ow.string
}));

Should both of these checks fail, or only one of them? It has quite some impact on the implementation.

from ow.

IssueHuntBot avatar IssueHuntBot commented on May 19, 2024

@sindresorhus has rewarded $54.00 to @SamVerschueren. See it on IssueHunt

  • 💰 Total deposit: $60.00
  • 🎉 Repository reward(0%): $0.00
  • 🔧 Service fee(10%): $6.00

from ow.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.