#Autocompletion for keyof object but also allow any string, and infer the type from union in a switch

60 messages · Page 1 of 1 (latest)

pliant schooner
#

Hello everyone, I should've probably split this in two separate posts as they're two separate issues. The code has comments that describe the issues, but in summary,

  1. My union types are not properly being inferred when using a switch statement, I have a mapping of key -> value and when I switch on the key i still get a union of value | value2 | value3 ...
  2. I want to support having keyof T, but also allow any string, which when written as T extends keyof T | string loses the autocompletion for the IDE
odd dewBOT
#

@pliant schooner Here's a shortened URL of your playground link! You can remove the full link from your message.

Volks#8167

Preview:```ts
type HubCapsule<E = string, T = any> = {
channel: string
payload: HubPayload<E, T>
}

type HubPayload<E = string, T = any> = {
event: E
data: T
}

type HubCallback<E = string, T = any> = (
capsule: HubCapsule<E, T>
) => void

type ChannelEventPayloadMap
...```

timid scaffold
#
  1. I want to support having keyof T, but also allow any string, which when written as T extends keyof T | string loses the autocompletion for the IDE
    don't talk about "autocompletion"
#

you are not aiming for autocompletion, you're aiming at type-safety

#

and that type safety allows you to have autocompletion inside of you editor

#

anyway

#

what you are asking for is not possible

#

"foo" | string will always resolve to string
since "foo" is already included in string

#

the same way Infinity + 1 equals Infinity
your exact value or litteral is already part of the bigger "group"

pliant schooner
#

Yeah that makes sense, you can discard the 2 problem, doesnt make sense

#

Do you have any idea about the 1st one? @timid scaffold I don't quite understand what's happening with my type composing

odd dewBOT
#
Ascor8522#7606

Preview:```ts
type HubCapsule<Event = string, Data = any> = {
channel: string
payload: HubPayload<Event, Data>
}

type HubPayload<Event = string, Data = any> = {
event: Event
data: Data
}

type HubCallback<Event = string, Data = any> = (
capsule: HubCapsule<Event, Data>
) => void
...```

timid scaffold
#

line 18

#

if Event extends Channel extends keyof Map is false, then Event is of type string

#

then, later, on line 21, doing Map[Channel][Event],
with Channel as keyof Map and Event as string & keyof Map,
so Map[keyof Map][string]
you get number | { field1: boolean; field2: number; }

#

sicne event2 is of type number

#

@pliant schooner

#

basically, checking that's it's a keyof Map[Channel] doesn't exclude the fact it's also a string

pliant schooner
#

Ohh, totally makes sense

#

Couldnt figure that out

#

Any way to alter my approach to make it work as I expected it would?

#

I like the naming convention, makes it much more readable also, I'll pick up that

timid scaffold
#

I'm not 100% sure about the origin of the problem tho

#

seems weird the keyof Map[Channel] check passes, but used as string when accessing Map[Channel][Event]

timid scaffold
eternal leaf
#

Youll have to ditribute over the hubthing

#

its just gemerating hubpayload<unionofkeys, unionofpayloads>

#

instead of a union of hubpayloads

#

can help more because i’m on ios and the playground is a nightmare on ios

pliant schooner
#

Sorry @eternal leaf, that went over my head, I am in no hurry, would love to get some more info when you get the chance

eternal leaf
#

ok

#

yeah it’s a simple solution but due to the way you structured your code it requires too many small changes to explain shortly

#

but if it would help you just have to use distributive conditional types to generate 1 hubpayload per data & event pair

#

instead of 1 hubpayload with all of them in it

dire maple
# timid scaffold > 2) I want to support having keyof T, but also allow any string, which when wri...

Worth noting that in many cases, providing autocomplete is distinct from type safety.

There are lots of APIs that will give you a type error if you make a mistake but won't provide completions for you.

Also TS has a lot of unique rules about how completions are generated so in some cases it is definitely a distinct problem. keyof T | string is actually a good example of a case where the goal is explicitly autocomplete because anything beyond string adds nothing to type safety

#

(assuming the intent is that keyof T should be a union of strings, at least)

pliant schooner
#

@dire maple This is an DX update to a type-less library, so I wanted to have autocompletion for specified values and let any for others. As you've said. But this doesn't seem possible

dire maple
pliant schooner
#

Interesting @dire maple , thanks,

dire maple
#

It's a well known hack in TS for this situation. Initially recommended by someone on the TS team years ago. It's used in tons of places so will definitely continue to behave the same way.

pliant schooner
#

Thanks everyone, great community

odd dewBOT
#
angryzor#9490

Preview:```ts
type HubPayload<Event = string, Data = any> = {
event: Event
data: Data
}

type HubCapsule<P extends HubPayload = HubPayload> = {
channel: string
payload: P
}

type HubCallback<P extends HubPayload = HubPayload> = (
capsule: HubCapsule<P>
) => void
...```

eternal leaf
#

Bit cleaner:

odd dewBOT
#
angryzor#9490

Preview:```ts
type HubPayload<Event = string, Data = any> = {
event: Event
data: Data
}

type HubCapsule<P extends HubPayload = HubPayload> = {
channel: string
payload: P
}

type HubCallback<P extends HubPayload = HubPayload> = (
capsule: HubCapsule<P>
) => void
...```

eternal leaf
#

@pliant schooner

pliant schooner
#

@eternal leaf thanks, will go over it, sorry you posted at 3am at my place 😂

#

Also reps for the others, thanks @dire maple @timid scaffold

#

Sorry for the pings, thought it would give you rep or something

lament sandal
#

alternatively you can react with rep on any of their messages

#

(ideally the one that was most helpful but doesnt really matter)

pliant schooner
#

@dire maple sorry for the ping, do you have any idea why the autocompletion trick is not working here? https://tsplay.dev/NdvknW

I understand how the trick works and so I am not sure why it's not autocompleting here. Only thing that's on my mind is that the keyof might be messing with it.

It should autocomplete the keys of the chan and chan2

dire maple
pliant schooner
#

Yeah sorry, didn't specify that it has to be 3.8

#

So I guess its just not working in that particular version, and I'll have to figure something out

dire maple
#

I notice also in the TSPlayground env it doesn't autocomplete until you type the first character. In my local env it autocompletes even if the string is empty

#

Yeah you may be able to, but I'd be testing stuff out and debugging it the same way as you since I've never worked with a version that old

pliant schooner
#

Thanks for the swift response @dire maple you gave me a lead

dire maple
#

I would recommend the approach I took overall though, should never give worse results and just removes having to duplicate the constraints on the T param