Compile-time typesafe merge/and for data-only "traits"
I've evaluating introducing arktype to a typescript codebase, but I got stuck trying to use it to set up my POJO "traits" system. This is similar in concept to the Trait abstract class in
arktype/util
but this is data only; so far I've avoided the need to introduce any classes and I'm hoping to maintain this approach.
So I have a discriminated union that represents the different "traits" and the union members share a common shape (mainly references to other trait names), something along these lines:
I'm confused about how I would represent this setup in arktype in a typesafe manner? Or would you suggest an alternative way of representing this? I don't have any significant code written against these types so I'm open to rethinking this setup entirely.
I got stuck almost immediately as neither .and(...)
nor.merge(...)
will allow me to inherit compile-time type checking of requires
in my Trait
subtypes.
Please help! Thanks24 Replies
What specifically do you want to work that doesn't?
I guess you want a way to inersect two objects so that the traits arrays can be intersected as sets?
There's an API for writing arbitrary type-level logic as a generic:
oh
If you're wanting to map over two objects and intersect them except the
traits
key which you want to treat as a set instead of an array, I guess I'd say merge
them then go back into the type and replace the requirements
key by manually concatenating the lists
The easiest change to the API you could make that would make this trivial was just having your trait sets be an object instead of a tuple e.g. {HasMouth: true, TraitCanScream: true}
then you can intersect them without worrying about itMaybe that's the solution, I had in my head that I would be able to get what I wanted without the ark equivalent of the
TraitDefn
generic above, but it's likely that ark needs it to be generic for the exact same reason TS needs it i.e. TS won't type-check the requires
with &
either:
Yeah, best to use an object to simplify things tuples are treated positionally so intersecting them will make the type unsatisfiable if you have multiple literals
If you do that you will just be able to intersect them normally and the inference will be fine
@ArkDavid so how would you represent
type TraitDefn<T extends Trait> = Trait & T
in ark?That doesn't do anything since
T
extends Trait
intersecting should be a no-opI'm looking at
If you want a generic with constraints you can do
generic(["T", yourTraitType])("T")
it's what's giving me type-checking in
I meant the
Trait & T
part it should just be T
ah
yes
you're right
@ArkDavid ok that generic thing got me further! but now I'm having trouble when the requires isn't an empty array:
Name should be
"'TraitCanScream' | 'TraitHasMouth'"
like TS or you can use type.enumerated()
and pass them thereI know there's a lot missing from the docs but do check those out and see if some of what you're looking for is there https://arktype.io/reference/api/
This worked!
I don't understand the difference though