sindresorhus / ow

Function argument validation for humans
https://sindresorhus.com/ow/
MIT License
3.81k stars 108 forks source link

Nullable modifier #163

Open Riim opened 5 years ago

Riim commented 5 years ago

ow.nullable.string instead of ow.any(ow.string, ow.null)

A generic modifier for |null|undefined would also be useful. Maybe it is better if optional will also allow null? In most cases, you need |null|undefined and |null. Separately, |undefined is needed almost never.

sindresorhus commented 5 years ago

We are unlikely to add this as we feel null should not be used in general. See: https://github.com/sindresorhus/meta/issues/7

Riim commented 5 years ago
  1. It is not always possible to refuse null. For example, I check the server response and GraphQL really likes to send null. My server developer are unlikely to be inspired by the idea of abandoning null.
  2. Sometimes it is possible to use null to your advantage. Example: undefined - data was not requested from server, null - requested, there is no data. This works great for me.
  3. It is unlikely that more than 5-10 lines of code (without tests) will be required to implement this; this is really a simple functionality.
mnmkng commented 5 years ago

I'd also like to support the idea of having a nullable validator. Even though I generally agree with https://github.com/sindresorhus/meta/issues/7, null is out there in the wild and since dynamic type-checks mostly exist for validating input that is provided at runtime, I feel that we can't just discount null on the basis of code-style preference.

Originally, I wanted to submit an issue to discuss standardization of exception messages, but having a nullable validator that'd merge the message would work as well.

Current:

ArgumentError: Any predicate failed with the following errors:
- Expected property `foo` to be of type `null` but received type `Object`
- Expected `foo` to be of type `number` but received type `Object` in object

Preferred:

ArgumentError: Expected property `foo` to be of type `number` or `null` but received type `Object`
Riim commented 5 years ago

Sorry for my english and my persistence.

Why not use the following syntax instead of any:

ow.number.or.string;

? This allows you not to break your fingers once again by typing brackets and solves the problem with null:

ow.number.or.null;
ow.number.or.null.or.undefined;

It is also not clear why need the types for int8Array,uint8Array, nan, etc.? Such libraries are usually used at the junction of code bases. Like the following:

  1. The client part of the application receives data from the server and checks this data for changes in the API.
  2. On the contrary: the server checks the incoming parameters to immediately stop processing the request if the parameters are incorrect.
  3. Data is validated before being sent to the database, for example, in my ORM joi is used for this.

In all the above examples, no int8Array is possible. Maybe for smaller size it's better to limit types to possible in json plus undefined and maybe some commonly used types?

UPDATE: I suddenly read the first line in readme and realized why ow is what it is. It's just for other tasks. This is the fourth attempt to find a validation library suitable for my tasks. Before that there were type-check, joi, yup. Looks like I'll have to write it himself ((.

UPDATE2: Probably a bit crude implementation, but already quite working: @riim/type.

sindresorhus commented 4 years ago

I have changed my mind. It does indeed make sense to add this here as you can't control what other APIs use. PR welcome.

I still want a link to https://github.com/sindresorhus/meta/issues/7 in the docs to try to convince people to not use null in their own APIs though.

sindresorhus commented 4 years ago

I wanted to submit an issue to discuss standardization of exception messages

You should still open an issue about this for other use-cases. We've tried to keep the messages consistent, but I'm sure we missed some cases.

sindresorhus commented 4 years ago

Why not use the following syntax instead of any: ow.number.or.string;

I don't remember exactly why we didn't do it this way. It does look nice, but there are ambiguous cases:

ow.string.length(3).and.string.uppercase.or.string.includes('f')

Does this mean it accepts (ow.string.length(3) && string.uppercase) || string.includes('f') or (ow.string.length(3) && (string.uppercase || string.includes('f')) ?

Riim commented 4 years ago

In omyumyum i use .custom() to transfer priority to .or. For example, an object may contain either a field age or field birthday:

om.object.shape({ name: om.string }).and.custom(
  om.object.shape({ age: om.number })
    .or.object.shape({ birthday: om.date })]
);