-
Notifications
You must be signed in to change notification settings - Fork 1
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
Recursive type #18
Comments
Hi!, You're right You can still write a predicate (boolean returning function) for that case and use it alongside and with, other type-validations |
Simple example if you can live without rejections: const isFoo = recordOf(maybe(
// `isFoo` is wrapped with a function - so it finishes to initialize, but can still be referenced by `anyOf`
anyOf(string, (value: unknown): boolean => isFoo(value))
)) If you have to get rejections, you can use the more elaborate code const isFoo: TypeValidation<Foo> = recordOf(maybe(anyOf(
string,
registerRejectingValidator(
(value: unknown, reject): value is Foo => isFoo(value, reject),
'Foo',
(transform, args) => isFoo[transformValidation](transform, args)
)
))) I'm aware this is suboptimal, and intend to create a built-in for recursive types - but for now I hope this helps |
@ShlomiAltostra Thank you for the input, I didn't know that I may pass in a simple boolean function (or type guards for that matter). Thank you! |
@ShlomiAltostra Turns out, that this is not working as expected: import { anyOf, primitives, recordOf } from "@altostra/type-validations";
interface Foo {
[key: string]: Foo | string | undefined;
}
export const isFoo = recordOf({
key: primitives.string,
value: anyOf(
primitives.undefinedValidation,
primitives.string,
(data: unknown): data is Foo => isFoo(data)
),
});
test("isFoo", () => {
expect(isFoo({ foo: "bar" })).toBe(true);
expect(isFoo({ foo: [{ bar: "1337" }] })).toBe(false); // FAILS!!!
}); This is somewhat unexpected to me. The array should not valid. |
@aomader |
I totally understand that this is technically correct. Yet, I highly doubt that people would consider this a good default behavior nor an expected one. const rndm: Record<string, unknown> = ["asd"]; |
This is mostly about API ergonomics and communicating the intent. The function is called Additionally, there is an To be honest, I think this is a big problem. This somewhat widened the allowed range of input data quite a bit without me noticing, since the behavior somewhat deviates from TS. |
Considering the MWE from above again: test("isFoo", () => {
// this checks out
expect(isFoo([])).toBe(true);
// but this does not even compile
const foo: Foo = [];
}); I find this discrepancy unsettling. |
Yet, as you can see, the problem is not that After checking for What is concerning for you? |
Well, the code you are using is not the one I'm talking about. Again, to show it in its full glory: import { anyOf, primitives, recordOf } from "@altostra/type-validations";
interface Foo {
[key: string]: Foo | string | undefined;
}
export const isFoo = recordOf({
key: primitives.string,
value: anyOf(
primitives.undefinedValidation,
primitives.string,
(data: unknown): data is Foo => isFoo(data)
),
});
test("isFoo", () => {
// this checks out
expect(isFoo([])).toBe(true);
// but this does not even compile
const foo: Foo = [];
}); And obviously something that does not compile should also not validate. |
Hej,
how would you handle a recursive type, for example somethling like:
Currently, I do not see a way to express this.
The text was updated successfully, but these errors were encountered: