How to build generic functions that use ArkType schemas?
I was a bit confused why this doesn't work. I seem to remember that it did work in an earlier version of ArkType. As soon as I replace
Type<T>
with Type<{}>
in the signature it works 🤔36 Replies
I do recall an issue with this in the past. I haven't made any changes to this recently, but if anything it should be opened as a bug on the TS repository anyways.
Type
is a conditional, but all branches evaluate to an object extending BaseType
which has all the core properties and call signature of Type
, so TS should always be able to infer that at least those are there.
Maybe @Andarist has some ideas about the fallback that's going on here that's causing it to infer as unknown
, but in my experience, TS is very unreliable at inferring values associated with conditional parameters regardless.
In the meantime, you can workaround this either via having an internal and external signature or casting, as mentioned recently in a similar thread:
https://discord.com/channels/957797212103016458/1247663057610604717/1332144190137700353at the very least please provide a TS playground with this code in it
it's a start for just any investigation
I already hit my playground quota for the week 😛
I meant that @Luca Schultz should copy-paste this into one :p
That sounds like a good plan 😅
Sorry if my question sounded entitled. I genuinely wasn't aware whether what I was doing should work, so this wasn't meant to be a bug report.
BUT since you asked: https://www.typescriptlang.org/play/?#code/JYWwDg9gTgLgBAbzgFQJ5gKYBo43RuAXzgDMoIQ4AiAQygGs9MqAoFkgVwDsBjGYCFzhg6AZwwAeZAD44ACh6CSwAOYAuRCzhxRPABYYQNDWkxTpWLXABuNADYcMG7vS4QA7lxaEAlJu2KXKLwUBiiHHbwALxwgcoqAHS6BkYKSqoJtg4YPmzawCTyoeGRcMBBMDS8GBCFTBgJGFDkUKJ+CFbaMHrk7nBcGH0Aos3QcgAGAJJcWcAAJjb2jhoAJAjFETAJIGGiNCoYhOO52oR5cKEwHFBCG5HeQA
Thank you guys for the quick replies ✌️
TS Playground - An online editor for exploring TypeScript and JavaS...
The Playground lets you write TypeScript or JavaScript online in a safe and sharable way.
I get a crazy number of questions about wrapping generic parameters. It's not users' fault- the inference often feels imprecise or sometimes just wrong. I guess I should write up an FAQ entry
The intuitive thing for me is that this doesn't yield the same type of error?
Type<T>
replaced by Type<unknown>
@ArkDavid if this is the same issue as the one im thinking of: u should move that
NoInfer
out of Type
this is really meant to be a signature-specific "annotation"
and not something that u put in typesNoInfer
from instantiateType
(locally in the .d.ts
) and that seems to work 👀If you can find a way to fix my NoInfer usage without breaking the other tests I'd be extremely grateful 😅
TBH I still have absolutely no mental model for the whole return type inference thing
It seems so counterintuitive
I remember that last time I tried to remove it, it broke the mapping API https://github.com/arktypeio/arktype/blob/de5bce880a529cf94d3c107479a208105db6694d/ark/type/__tests__/objects/mapped.test.ts
GitHub
arktype/ark/type/tests/objects/mapped.test.ts at de5bce880a529c...
TypeScript's 1:1 validator, optimized from editor to runtime - arktypeio/arktype
Maybe there's a way that could be changed to that the problem didn't occur? It was something that felt crazy wrong though like you returned
type("number | null")
and somehow it just inferred number
and allowed iti;m not saying u should remove it entirely
u should move its location
I thought we tried to fix this though and couldn't
Maybe the issue was that if it wasn't included there, it would have to be added to dozens of signatures?
ye, this might be the problem u have wanted to avoid
but u shouldnt try to avoid it ;p
like i said - this, despite being a type wrapper, is really designed like a signature-level annotation
so it belongs to signatures and thus it has to be used in each signature
:S
like, think about it as:
I just don't get why you'd ever want to infer from the return type
TS Playground - An online editor for exploring TypeScript and JavaS...
The Playground lets you write TypeScript or JavaScript online in a safe and sharable way.
Hey guys, I appreciate the quick turnaround, but I'm a bit confused. Do you need me to open a bug report on the Arktype repository? @ssalbdivad you mentioned that:
if anything it should be opened as a bug on the TS repository anyways.is that still the case? Also is there a good workaround I can use?
Yeah no need for a bug, I will look into Andarist's suggestion but generally I'm not making any guarantees about how generic parameters are treated within functions- that is a TS issue.
Yeah see my original response for a workaround
Thanks, I'll check it out
Yeah, this is kind of what I imagined. It's cool that it works in this case but to me it really breaks the model of inner functions needing to have enough information to infer their own inputs.
It feels like most related scenarios you can't rely on this (the one I think about most is
const obj: Obj = Object.assign(partial, {somePropOnObj: (In) => true})
), and it creates very confusing results in cases like this one in ArkType, so on the whole I really just which this didn't exist at all.
Maybe it is really important for certain other APIs though
I guess it also relates to the idea that in cases like:
I always have to tell people to not inline the second type because the fact that the outer inference can affect the behavior of the inner function can break things and often makes them much less efficient.
My intuition is it would just be cleaner if the inner function call and result were fully evaluated bottom up and then the output were just evaluated by the outer type, without the inner definition being affected at all by whether it is wrapped in another type
or noton one hand TS is somewhat limited in generic contexts, on the other hand - it's sometimes surprisingly capable
specifically, in here, it doesnt trip over generic parameters per se
Handling values in a class/function with a generic parameter in their type? I've often found that pretty hopeless
it's the unresolved deferred conditional type that u introduce there
and that's just a fallout of using NoInfer and trying to also unwrap types from it automatically for readability purposes
(iirc)
too many tricks applied at once and u got urself an unwanted side effect of that combo ;p
unwanted side effectnice phrase for a bug 😛 Here's another good example where TS's reasoning on generic parameters is bad: https://github.com/microsoft/TypeScript/issues/44645#issuecomment-1517044304 It feels like the representation is very convoluted in a way that leads to lots of weird errors and inference. I would honestly just expect it to treat the value as the base constraint, then force you to cast the return if it can't be inferred (which it usually can't) I guess now there's some level of conditional inference, but that hadn't even been introduced at the time of this issue @Andarist This is a great example of the kind of stuff I run into when I'm dealing with values that reference generic params
Like I have absolutely no idea what is going on here
What is it even complaining about?
I don't know how to get TS to complain about a spread type like that in any other context, there's no declared type
no idea how
merge
is implemented ;p
but i guess this is weird because u dont even have a type annotation?Right exactly
It doesn't even matter
And I see stuff like this a lot where errors just don't even fundamentally makes sense, not just aren't able to understand relationships or something. Just stuff that isn't consistent with how values behave in TS in general
I'll chime in that I also see this but with an error calling out
exactOptionalPropertyTypes
And it seems to only show up in similar(-ish) contextsYeah I see these super often also. For certain assignments, TS will give many lines mentioning EOPT but the actual issue has nothing to do with EOPT
Some bad heuristic check to determine whether that bad should be included
If you search for
exactOptionalPropertyTypes
in this Discord you will probably find many messages of @TypeHoles and I discussing that exact scenarioEopt implantation is wacky, especially the error messages where they generate the normal error messages and translate them to the eopt ones post hoc