Comments (5)
I packaged my filtering into a small lib in case it's useful for anyone else. runtypes-filter
.
Usage:
import { Literal, Number, Record } from "runtypes";
import CheckFilter from "runtypes-filter";
const Asteroid = Record({
type: Literal("asteroid"),
mass: Number
});
const filterAsteroid = CheckFilter(Asteroid);
const untrustedAsteroid: unknown = {
type: "asteroid",
mass: 100
};
const trustedAteroid = filterAsteroid(untrustedAsteroid);
from runtypes.
I think this is a feature that I want or similar. I’d like a clone()
or copy()
provided by runtypes which only copies the properties known by runtypes for a particular type. As the OP mentions, this would be useful in APIs. For example, I might have a RunType
defined with properties I am willing to expose to a client in response to a request. But if I get the data from the database, it might include extra information which shouldn’t be disclosed to the client.
This library already has logic to iterate over properties in its check()
. It’d be great if it could reuse this same logic to do a copy()
that contains only properties specified in the runtype to sanitize output/avoid accidental disclosure of private data.
from runtypes.
That makes sense. I think it should be possible to write such a function against runtype's Reflect
API. If so, I would say that it makes sense to define it as a separate library, so as to keep the core of runtypes as simple as possible. What do you think?
from runtypes.
Can you be more specific about what you're proposing, maybe with some example code? It's not clear to me what you mean by sanitization in this context.
from runtypes.
This is what I threw together real quick. It's not complete, but covers the types that I needed.
function assertUnreachable(_x: never): never {
throw new Error('Uncovered branch');
}
function filter<T, R extends Runtype<T>>(t: R, x: T): T {
const r = t.reflect;
switch (r.tag) {
case 'instanceof':
case 'intersect':
case 'function':
case 'unknown':
throw new Error(`Type "${r.tag}" is not filterable`);
case 'never':
case 'literal':
case 'boolean':
case 'number':
case 'string':
case 'void':
case 'symbol':
return x;
case 'array':
return (x as any).map((v: any) => filter(r.element, v));
case 'tuple':
return (x as any).map((v: any, i: number) => filter(r.components[i], v));
case 'dictionary':
return Object.entries(x).reduce((acc, [k, v]) => ({
...acc,
[k]: filter(r.value, v)
}), <T>{});
case 'partial':
case 'record':
return Object.entries(r.fields)
.filter(([k]) => x.hasOwnProperty(k))
.reduce(
(acc, [k, v]) => ({
...acc,
[k]: filter(v, (x as any)[k] as any)
}),
<T>{}
);
case 'union':
const alt = r.alternatives.find(a => a.guard(x));
return filter(<any>alt, x);
case 'constraint':
return filter(<any>r.underlying, x);
case 'brand':
return filter(<any>r.entity, x);
}
assertUnreachable(r);
}
// Usage
const Thing = Record({
a: string,
b: number
});
const thing = { a: 'a', b: 1, c: 'extra' };
const filteredThing = filter(Thing, thing);
The most notable type that is missing is intersect
. Intersect is weird because it supports polymorphic data that may or may not be filterable. For example, a string
with properties set on it. The only straight forward approach that I could think of is create a version of filter
for intersect
that specializes on certain common monomorphic intersections (e.g., Record
).
Another significant limitation is that this will explode at runtime for types that can't be filtered. This is fine for me because I'm using it on config loading. However, this could also be worked around by creating a filter
method for the type that you need to filter
. An exception could be thrown when generating the filter
method--which would likely be at a top level that happens on start up. Something like,
const filter = filterable(Thing);
const filtered = filter(thing);
from runtypes.
Related Issues (20)
- Is there a way to omit everything that's not defined by the Record instance? HOT 1
- Create runtypes from existing TypeScript types? HOT 1
- Printable form of type from runtype? HOT 1
- Unuseful error message on typechecking HOT 1
- Cannot validate optional+null circulare fields HOT 4
- Optional types in Tuple HOT 1
- How check for ObjectId? HOT 3
- Function which accepts a runtype and omits some fields HOT 1
- `omit` properties of a `Constraint` or `Intersect`? HOT 2
- Constraint::reflect does not expose .underlying
- Support for Set type HOT 2
- [Feature Request] Type Guard for ValidationError HOT 2
- Option to return errors instead of throwing them for performant validation. HOT 4
- Runtypes-like `.guard()` HOT 1
- How do I exclude undefined properties from record? HOT 2
- Is it possible to have more than one brand HOT 2
- Type validated by Dictionary is different than returned type
- How do I define an array which is optional yet in case it was defined it shouldn't be empty ? HOT 2
- Performance
- Publish to deno.land/x HOT 4
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from runtypes.