#Switch statement with multiple possible type values

31 messages ยท Page 1 of 1 (latest)

wild pagoda
#

Hi, I've been working on something that requires building a particular type of object for a game: a two-headed chimera. I ended up with something like this (see below):

The idea with this is that I can build a chimera step by step, including assigning skills to each head separately. In this simple example, a fire skill would be assigned to the left head while an ice skill would be assigned to the right head. This works as expected but TypeScript seems to think that both skills are assigned to the left head.

I've tried all I can think of but this is about the extent of my TypeScript abilities. Any help is much appreciated. Please let me know if something isn't clear. Thank you.

minor stagBOT
#
joao6246#0

Preview:```ts
type ChimeraElement = "fire" | "ice"

type ChimeraHead = {
element?: ChimeraElement
}

type Skills =
| "fi
...```

fleet walrus
#

I'm a bit confused on the idea here, if it's hard-coded that withSkill and ice elements go on the right and fire skills go on the left, I'm not sure what the builder pattern helps with.

#

With the current API... probably there's a way to fix it so that TS doesn't assume everything goes onto the left head... but the 'fix' would be that TS doesn't know which head has which skill. (Which is more safe but still not very useful)

#

If hardcoded "fire = left, ice = right" is really the goal you'd probably need something pretty complex and un-type-safe for TS to understand that at a type-level.

#

Maybe if your builder had a pattern like:

.withSkill({
   left: /* skill to assign to the left head */
})

then it'd be more plausible for TS to have good typings.

#

But TBH, my guess is that this just isn't a good place to use the builder pattern.

wild pagoda
#

Hi, sorry for the delay I only posted this as I was getting some sleep.

I'm using the builder pattern because I've been using it for other similar types, and there are other properties where it makes sense. I agree that ideally the position of the heads should be irrelevant, but I was trying to narrow things down in an attempt to make TypeScript work. I've tried other things like comparing the element of the skill against the element of each head, but without any luck.

#

If possible I'd like to do this without having to re-write everything, since it works as expected at runtime. I could consider using this approach if everything else fails:

.withSkill({
   left: /* skill to assign to the left head */
})

But this is more explicit than I'd like to be. If in the future I wanted to had a third and fourth heads, it gets cumbersome quickly. The goal is to have something simpler like this:

.withSkill(someIceSkill)

and have it automatically detect where it fits internally. For now, the only reason I'm using left/right is to try and make this work.

sullen mantle
#

in case this is an XY problem, can you explain why you need this to be the case?

a fire skill would be assigned to the left head while an ice skill would be assigned to the right head
if there's a specific gameplay reason for that then fair enough, but if all you really need is a rule like "fire and ice elements don't mix on the same head" then i think things could be simplified

wild pagoda
#

There's no reason for that to be the case. I was trying to explained what I've tried, which as of my last attempt was to hard code each side to a particular element. But there's really no need for that, and I would prefer not to have it that way as is more restrictive in case I want to expand things later on. What you are saying is quite accurate: fire and ice elements don't mix on the same head. At this time I only plan on having one skill per head, but I would like to eventually have more, although always of the same type.

sullen mantle
#

cool, in that case it might help to think of them as "the fire head" and "the ice head" and just directly use skill.element as the key (instead of mapping elements to left/right)

#

i'm in the middle of something but can try to provide an example in a bit

wild pagoda
#

Thanks, I appreciate it. No rush at all, this is a side project... one of many ๐Ÿ˜‚

sullen mantle
#

here's an example:

minor stagBOT
#
mkantor#0

Preview:ts type ChimeraElement = "fire" | "ice" type SkillName = | "fireBreath" | "ember" | "icePath" | "iceScale" type Effect = (...args: never) => unknown type Skills = Partial<Record<SkillName, Effect>> type SkillSpecification = { name: SkillName element: ChimeraElement effect: Effect } ...

sullen mantle
#

do note that Object.assign is inherently unsafe, so be careful when you make changes to that part of the code

#

a different approach would be to have withSkill do something simple like push the new skill to an array, then do the transformation/merge stuff in build

wild pagoda
#

This works great! Thanks!

#

I've read that a few times about Object.assign and I was wondering if that might have been the issue.

#

I'll play around with this a little bit and see if I can simplify things. My only goal for now is to have that TS support, which this seems to do fine.

wild pagoda
sullen mantle
#

yes, though spreads have gotchas too (but fewer than Object.assign)

#

i don't usually use classes in my code so initially wrote this out of habit/ignorance, which typechecks but doesn't work at runtime

wild pagoda
#

I love it that it adds a new head once the skill type is new. I'm gonna have to spend some time learning from this, TypeScript is really arcane wizardy to me, even for simpler cases ๐Ÿ˜„

#

Again, thanks a lot. If I finish it, I'll definitely add you to the credits

sullen mantle
#

you're welcome! shoot me a link to the finished product too, i'm curious to see what the actual gameplay is like

#

(but if your side projects are anything like mine there's a ~90% chance it'll never be finished ๐Ÿ˜… (not that there's a problem with that))

wild pagoda
#

Yeah... let's be real that's likely the case here ๐Ÿ˜› It initially started as an excuse to apply some DSA, design patterns, etc. Now I'm using it as an excuse to learn TypeScript more in depth.

#

There's no game as of yet, not even started in fact... I'm just creating random "sketches" if you will, in the form of code. Eventually, I'd like to put together sort of card game, similar to Final Fantasy's VIII and/or IX.