typescripttypescript-never

TypeScript InteliSense, how to hide variables of type never?


How can I hide certain type attributes based on generic parameter from InteliSense?

Problem

I have a generic type that takes different forms based on the generic parameter and marks some attributes as never if the generic parameter is not X, otherwise it assigns the attribute the type Y, like in this minimal example:

export type WorldEventType = {
    Notification: 11,
    Chat: 23,
}

export type WorldEvent<EventId extends keyof WorldEventType> = {
    eventType: WorldEventType[EventId]
    notificationArgs: EventId extends 'Notification' ? NotificationArgs : never
    chatArgs: EventId extends 'Chat' ? ChatArgs : never
}

export type ChatArgs = {
    message: string
    isPrivate: boolean
    targetLocalPlayerId: number
}

export type NotificationArgs = {
    message: string
}

This way, I can get different Event Types WorldEvent<'Chat'> and generate other types. Note that the data structure is given by the API and I can't control it, however I can change the types of the upper given generated code. I have tried looking into Type Overloading, other intelisense problems, but no problem seems to be specifically tied to InteliSense showing the never variables.

Images

enter image description here enter image description here enter image description here enter image description here


Solution

  • One way to approach this is to make a mapped type that removes all properties of type never.

    We can do that by making the key in the mapped type be never.

    In code it looks like

    export type WorldEventType = {
        Notification: 11,
        Chat: 23,
    }
    
    type RemoveNeverProperties<T> = {
      [K in keyof T as T[K] extends never ? never : K]: T[K]
    }
    
    type WorldEventImpl<EventId extends keyof WorldEventType> = {
        eventType: WorldEventType[EventId]
        notificationArgs: EventId extends 'Notification' ? NotificationArgs : never
        chatArgs: EventId extends 'Chat' ? ChatArgs : never
    }
    
    export type WorldEvent<EventId extends keyof WorldEventType> = RemoveNeverProperties<WorldEventImpl<EventId>>
    
    export type ChatArgs = {
        message: string
        isPrivate: boolean
        targetLocalPlayerId: number
    }
    
    export type NotificationArgs = {
        message: string
    }
    
    type Foo = WorldEvent<"Notification">
    

    which gives us

    type Foo = {
        eventType: 11;
        notificationArgs: NotificationArgs;
    }
    

    Note that this will not remove nested properties of type never.