https://github.com/poteto/validated-proxy
Typesafe, validated ES2015 proxies
https://github.com/poteto/validated-proxy
es2015 proxy typescript validations
Last synced: 10 months ago
JSON representation
Typesafe, validated ES2015 proxies
- Host: GitHub
- URL: https://github.com/poteto/validated-proxy
- Owner: poteto
- License: mit
- Created: 2017-12-13T06:40:05.000Z (about 8 years ago)
- Default Branch: master
- Last Pushed: 2019-02-03T21:31:24.000Z (about 7 years ago)
- Last Synced: 2024-10-03T12:18:15.149Z (over 1 year ago)
- Topics: es2015, proxy, typescript, validations
- Language: TypeScript
- Homepage: https://poteto.github.io/validated-proxy/
- Size: 424 KB
- Stars: 11
- Watchers: 4
- Forks: 1
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE.md
- Code of conduct: CODE_OF_CONDUCT.md
Awesome Lists containing this project
README
# validated-proxy [](https://badge.fury.io/js/validated-proxy) [](https://travis-ci.org/poteto/validated-proxy) [](https://coveralls.io/github/poteto/validated-proxy?branch=master)
A validated proxy represents a set of valid changes to be applied later onto any object. Each change is tested against an optional validation, and if valid, the change is stored and applied when executed.
## Documentation
Latest documentation is available [here](https://poteto.github.io/validated-proxy/).
## Getting started
Install using `yarn`:
```
yarn add validated-proxy
```
Or using `npm`:
```
npm install --save validated-proxy
```
Then import it and create a new validated proxy:
```ts
import { validatedProxy } from 'validated-proxy';
import {
validatePresence,
validateLength,
validateNumber
} from '../path/to/validators';
const user = {
name: 'Billy Bob',
age: 25
};
const updatedUser = validatedProxy(user, {
validations: {
name: [validatePresence(true), validateLength({ min: 4 })],
age: [validatePresence(true), validateNumber({ gte: 18 })]
}
});
// valid changes
updatedUser.name = 'Michael Bolton';
user.name; // 'Billy Bob'
updatedUser.flush();
user.name; // 'Michael Bolton'
// invalid changes
updatedUser.name = 'a';
user.name; // 'Billy Bob'
updatedUser.errors;
// [
// {
// key: 'name',
// messages: ['name must be more than 4 characters'],
// value: 'a'
// }
// ]
updatedUser.flush();
user.name; // 'Billy Bob'
```
## Custom validators
A validator is a higher order function that returns a validation function. The validator can pass options to the validation function. The validation function is the function that is invoked when you set a value on the `BufferedProxy`.
Here's an example of creating a validator that validates if a value is of a given `type`:
```ts
import { ValidatorFunction } from 'validated-proxy';
type Primitive =
| 'boolean'
| 'number'
| 'string'
| 'symbol'
| 'null'
| 'undefined';
type NonPrimitive = 'object';
interface ValidatorOptions {
type: Primitive | NonPrimitive;
}
const validateTypeof = ({ type }: ValidatorOptions): ValidatorFunction => {
return (key, newValue, oldValue) => {
return {
message: `${newValue} is not of type '${type}'`,
validation: typeof newValue === type
};
};
};
export default validateTypeof;
```
Now you can use your validator like so:
```ts
import { validatedProxy } from 'validated-proxy';
import validateTypeof from '../path/to/validateTypeof';
const user = { name: 'Billy Bob' };
const updatedUser = validatedProxy(user, {
validations: { name: validateTypeof({ type: 'string' }) }
});
updatedUser.name = 123; // error
```
### Custom validator type safety
If you're creating a custom validator that relies on the new value to be of a certain type, you can specify it as a generic type parameter to `ValidatorFunction` (where `T` is the type of your new value):
```ts
import { ValidatorFunction } from 'validated-proxy';
interface ValidatorOptions {
is: number;
}
const validateLength = ({
is
}: ValidatorOptions): ValidatorFunction => {
return (key, newValue, oldValue) => {
return {
message: `${key} must be exactly ${is} characters`,
validation: is === newValue.length // `newValue` is a `string`
};
};
};
export default validateLength;
```
When a custom `ValidatorFunction` is narrowed to a certain type, it will not typecheck if you try to use the function against a key on the original object that does not have the same value type. For example, the `validateLength` validator only works on `strings` (`number` does not have the `length` property):
```ts
import validateLength from '../path/to/validateLength';
interface User {
name: string;
age: number;
}
const user: Partial = { age: 21 };
const updatedUser = validatedProxy(user, {
validations: {
age: validateLength({ is: 3 }) // [ts] Type 'ValidatorFunction'
// is not assignable to type
// 'ValidatorFunction |
// ValidatorFunction[]'.
}
})
```
More examples can be seen [here](/test/support).
## Custom error handlers
The error handler is a function that is called when an invalid value is set. This is in addition to the error that is already stored in the cache. By default, the error handler is a `no-op` (does nothing). You can specify a custom error handler; for example, you could throw an error, log error messages, send them to a server, etc:
```ts
const proxy = validatedProxy(original, {
errorHandler: errorMessages => { /** do something here **/},
validations: /** ... */
});
```
## Custom execution handlers
The execution handler is a function that is used to set the changes on the target object. By default, this is `Object.assign`. You can specify a custom execution handler; for example, you could use Lodash's `assign`, Ember's `set`, and so forth:
```ts
const proxy = validatedProxy(original, {
executionHandler: (target, changes) => { /** do something here **/},
validations: /** ... */
});
```