-
-
Notifications
You must be signed in to change notification settings - Fork 160
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
Types mapped from objects containing named functions do not generate validation for those members. #1302
Comments
Simpler version, that remove the
|
Narrowed it down further: typia doesn't correctly recognise keys that are functions in mapped types. However it DOES recognise property keys that are initialized to functions. Key observation:
Going back to the initial example (with the complexity of Parameters, extends, async), changing
...to...
...generates the correct validation. This demonstrates that the only issue here is that mapped keys defined by functions are for some reason not generating correct validation, even if they are mapped to data (such as to their parameters) I'll update the issue title to reflect this observation |
Canonical example, that shows that the function declarations vs function expression behave differently. import typia from "typia";
type Mapper<X> = {
[K in keyof X]: string
}
type V1 = {
foo(): void;
}
console.log(
typia.validate<Mapper<V1>>({ foo: 'foo' }),
typia.validate<Mapper<V1>>({ foo: null }) // INCORRECTLY PASSES
)
type V2 = {
foo: ()=> void;
}
console.log(
typia.validate<Mapper<V2>>({ foo: 'foo' }),
typia.validate<Mapper<V2>>({ foo: null })
) |
@samchon Perhaps https://github.com/samchon/typia/blob/master/src/factories/internal/metadata/emplace_metadata_object.ts#L179 should be:
? I've not yet worked out if this will have any other detrimental effects, as I'm having issues running |
Ok, so that "fix" breaks lots of code as it new tries (fails) to generate validators for all function members. Typia does not (at present) generate validation tests for function elements, as can be shown here (aside: a basic test here could be that So the issue is, from a type perspective, that type FunctionParameters<X extends { [k:string]: (...a:any)=>any }> = {
[K in keyof X]: Parameters<X[K]>
} ...fails because it's input is stripped of all functional members, even tho the resulting type contains only data members. I think there are only two approaches to fixing this, and I have little insight into which is the best to implement:
Given The only other way I can think of doing this is to leave the function members in place, and simply generate a null or trivial validation test for them (or the "aside" above), since the mapped type above will correctly generate data tests as the resulting type does not contain functional members. There's a strong chance I've over-complicated this case, as I'm still learning how typia is implemented. Any hints on how to progress this to a fix would be much appreciated 🙏 |
This playground link seems to narrow down the issue to a cover all cases (updated: 30/9/2024 to cover 'quux' case) Given that it can work as expected, depending on the function declaration style, I think the above explanation is too complex. It simply seems to depend on the syntax (and therefore TS AST node type), rather than some complication inclusion/exclusion mechanism. The workaround would be to use the property syntax |
import typia, { tags } from "typia";
typia.createIs<{
foo: [];
bar: never;
}>(); At first, the Also, checking only property typed function is not a bug, bug intended spec following the standard way. The member methods are defined in the class SomeClass {
public methodA() {}
public propertyFunctionB = () => {};
} |
The problem is the types:
....are logically equivalent, but behave differently in typia. import typia from "typia";
type ApiArguments<API extends { [k:string]: (...a:any[])=>any}> = {
[api in keyof API]: Parameters<API[api]>;
}
type V1 = ApiArguments<{
foo(x:number): void;
}>;
type V2 = ApiArguments<{
foo: (x:number)=>void;
}>
typia.is<V1>({foo:['x']}); // Incorrectly validates
/*
const $io0 = (input) => true; // NO VALIDATION OF `foo`
return (input) =>
"object" === typeof input &&
null !== input &&
false === Array.isArray(input) &&
$io0(input);
*/
typia.is<V2>({foo:['x']});
/*
const $io0 = (input) =>
Array.isArray(input.foo) &&
input.foo.length === 1 &&
"number" === typeof input.foo[0]; // CORRECTLY VALIDATES `foo`
return (input) => "object" === typeof input && null !== input && $io0(input);
*/ Playground A similar issue exists when the type is derived from |
Similarly, if you look at the generated code in the playground link in #1302 (comment), you will see there is no generated code for |
RE you comment above:
This is only true in a class declaration, not plain objects or types. |
@samchon - thank you for fixing the shorthand property issue 🙇 However, the original issue with an object containing a member function that is mapped to a data type remains in v6.11.1 |
📝 Summary
I have a set of types to validate arguments (and returns, tho not necessary to illustrate the issue) in an async API object. The TS types that extract the arguments, when passed to
typia.createValidate
does not reliably fail invalid arguments. Hovering over the type in the playground and copying the computed type DOES generate a working validator.Args
andArgs2
validate with the same resultsArgs
incorrectly passes an invalid value,Args2
correctly fails an invalid valueUPDATE: NB: Please see this comment for the simplified canonical example which demonstrates that mapped objects containing function declarations vs function expressions behave differently
⏯ Playground Link
If you click on the playground link above and hover over
Args
, you see it evaluates toThis type represents the possible ways the test API can be called (ie a single API, with it's associated parameters). It has been copied and pasted and assigned to the
type Args2
.When an invalid argument is passed to the return of
typia.createValidate<Args>()
, it is incorrectly validated as correct. When the same invalid argument is passed to the return oftypia.createValidate<Args2>()
, it is correctly validated as incorrect.In TS (and the Typia Playground),
Args
andArgs2
are identical, however the execution of the validation function is not.Included for completeness (same as the playground link):
The text was updated successfully, but these errors were encountered: