-
Notifications
You must be signed in to change notification settings - Fork 10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
export type classes #49
Comments
What would the use case for this be, and what would |
Related #29
It should contain exports for ObjectType, UnionType, OptionalType, StringType and etc. import { v } from './app/lib/core/schema-utils';
// I have 2-3 schemas for my entities: Domain, FormValidation/FormData, Database/ExternalApi
// domain entity
v.object({ id: v.number() });
// formValidation / FormData validation
// But this validation will fail if we pass data from api (schema above) as is.
v.object({
id: v
.string()
.map(Number.parseInt)
.assert((value) => value > 0),
});
// Lets you duplicate schema for working with incoming (form api) data too
v.object({
id: v.union(
v
.string()
.map(Number.parseInt)
.assert((value) => value > 0),
v.number(),
),
});
// What if api can return null/undefined? I need to convert this to `''`:
v.object({
id: v.union(
v
.string()
.nullable()
.chain((value) => {
if (!value) return v.ok(Number.NaN); // pseudocode here, not covers all cases. numbers, booleans, unions is pretty funny for handling null/undefined/booleanish values
return v.ok(Number.parseInt(value)) ?? '';
}),
v.number(), // fallback to value from API
),
});
// Finally, I decided to write a helper utility.
function field<T extends v.Type>(fieldType: T) {
// pseudocode heres
// returns v.union(inputType.chain((value) => fieldType.try(value)), fieldTyoe)
}
// We are here. I need a function that resolves original type and generates mapper from `inputType` to `fieldType if possible
// Resolves is a common function used in form libraries on the frontend (vee-validate, react-hook-forms, etc).
const fieldType = v.string().optional();
// ATM, I was forced to use constructions like, but I don't like it.
const resolveOriginalType = <T extends v.Type>(t: T) => (t.name === 'optional' ? t.type : null;
|
Probably the main and shortest point is that it will help users write smarter/safer utility functions or schema transformers. Now, of course, it is also possible to write one and I did so. But inside the function there are a lot of types structure feels like implementation detail, but I need to rely on them. But because they're not exported, I feel like I'm relying on them and things can break. If it's possible at the type level inside the library to fix this, that's ok too. In that case, I want to get some kind of union that would allow me to rely on name and x prop. With this solution I can avoid class exoption. const SafeType = { name: 'optional'; type: Type } | { name: 'union'; options: Type[] } | {name: 'object', shape?: ... } |
What I gather from this is that you want to define a type that's used internally in the system (the domain entity) and then use that to generate different input validators for different contexts (with typesafe type transformers). If that is correct, then exposing the types wouldn't be enough in itself without some significant supporting type machinery (e.g. to ensure that |
Yes, you got me right. Just a few comments: I've already written a library that works in my case. However, internally it relies on private and protected instance fields. This looks like a bit of a mess. To be honest, the idea of making classes public doesn't seem so straightforward. The internals can still change. What if we write a function that resolves the type and returns a type tree? Then you can keep the classes private, but users will be able to write their own transformers, and you as the library author will be able to change the implementation. For example: const name = v.string().nullable()
const tree = resolve(name)
console.log(tree)
// {name: 'string', nullable: true }
// or simpler, as types works
// {name: 'union', options: [ {name: 'null' }, {name: 'string'} ] } |
In the example Valita would be used as a general data definition language (to define the domain entity types from which the input validators are generated) which we have outlined to be outside the scope of this library. I recommend skipping the validator -> JSON conversion phase, and start from the JSON ( |
After writing some mini libraries, I realized that we need to export the classes so we don't have to use type assetions on every line.
The text was updated successfully, but these errors were encountered: