-
-
Notifications
You must be signed in to change notification settings - Fork 14
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
Adding closure support for circular types #39
Comments
Thanks! It's a nice use-case and we definitely want to support it more in the future. For now, I managed to solve it by explicitly define the type and create a function validator: type Node = {
name: string;
nodes: Node[];
};
const NodeSchema = (node: Node): Node => {
return Schema({
name: string.trim().normalize(),
nodes: array.of(NodeSchema),
})(node);
}; I added a test for it here: d77a442, 31c38e6 This const MainSchema = Schema({
type: string,
node: NodeSchema,
}); |
One way to handle this could be to pass in a function which will be called to evaluated the type: const NodeSchema = Schema({
name: string.trim().normalize(),
nodes: (self) => array.of(self),
}) And the function could also help in situations where you have circular types across multiple types: const SourceFilterOrSchema = Schema({
operator: 'or',
left: () => SourceFilterSchema,
right: () => SourceFilterSchema,
})
const SourceFilterSchema = Schema.either(
SourceFilterAndSchema,
SourceFilterOrSchema,
SourceFilterComparisonSchema,
) |
In case it helps, this is the schema I've created. This works, but as you can see in the comments, I'm unable to use the auto-typing for import Schema, {
Type, string, number, boolean,
} from 'computed-types'
const SourceFilterSchema = (node: SourceFilter): SourceFilter => {
return Schema.either(
SourceFilterAndOrSchema,
SourceFilterComparisonSchema,
)(node)
}
export const SouceFilterPrimitiveSchema = Schema.either(string, number, boolean)
export const SourceFilterAndOrSchema = Schema({
operator: Schema.either('and' as const, 'or' as const),
left: SourceFilterSchema,
right: SourceFilterSchema,
})
export const SchemaFilterComparisonOperatorsSchema = Schema.either(
'eq' as const,
'gte' as const,
'gt' as const,
'lt' as const,
'lte' as const,
)
export const SourceFilterComparisonSchema = Schema({
operator: SchemaFilterComparisonOperatorsSchema,
value: SouceFilterPrimitiveSchema,
})
export type SourceFilter = SourceFilterAndOr | SourceFilterComparison
export type SourceFilterAndOr = {
operator: 'and'|'or'
left: SourceFilter
right: SourceFilter
}
// If I try to use this instead of the above, typescript errors with: Type alias 'SourceFilterAndOr' circularly references itself.
// export type SourceFilterAndOr = Type<typeof SourceFilterAndOrSchema>
export type SourceFilterComparison = Type<typeof SourceFilterComparisonSchema>
export type SchemaFilterComparisonOperators = Type<typeof SchemaFilterComparisonOperatorsSchema> |
Also, with this approach I'm unable to mark the schema as optional. const SourceFilterSchema = (node: SourceFilter): SourceFilter => {
return Schema.either(
SourceFilterAndOrSchema,
SourceFilterComparisonSchema,
)(node)
}
const AltSchema = Schema({
filter: SourceFilterSchema.optional() // this does not work
}) |
I think recursive functions will break TypeScript validation and require type definition from the user, but I really like this idea! We can create const Node = Schema.recursive<T>((self: T) => ({
name: string,
children: array.of(self),
})); I will play with it when I have some time. |
That looks good! I think your approach makes sense for a recursive fn. The other use case is to enable SchemaA to reference SchemaB and vice versa (as below). In that case, we don't actually need the self variable - we're just using the fn to make sure we have a reference to later defined schema variable. const SchemaA = Schema({
b: SchemaB // ERROR: SchemaB is not defined
})
const SchemaB = Schema({
a: SchemaA
}) To solve the above, you could again use the const SchemaA = Schema.recursive(() => Schema({
b: SchemaB // Now it works!
}))
const SchemaB = Schema({
a: SchemaA
}) I wonder if the The other difference between |
maybe I liked your example. Function closure is really a strong concept in JavaScript. I wonder how TypeScript will handle that. |
hi 😺
i was getting amongst
computed-types
for a side project i'm playing with, and then i realized the types i want to validate are circular, e.g. a tree data structure. i was wondering if it might be possible to usecomputed-types
with circular types.i made a simplified example to show what i mean, and what i have working so far: https://repl.it/talk/share/circular-computed-types/43342
i'm able to get the runtime to work with a silly hack, but i'm stuck on getting the types to work.
was wondering, is this something that might be possible to do?
cheers! 💜
The text was updated successfully, but these errors were encountered: