Skip to content

Conditional type is not resolved when used in genericsΒ #51080

Closed
@orromis

Description

@orromis

Bug Report

πŸ”Ž Search Terms

conditional types, generics

πŸ•— Version & Regression Information

  • Seems to be broken in every version available in TS playground

⏯ Playground Link

Playground link with relevant code

πŸ’» Code

interface PayloadMap {
    hello: string,
    none: never,
}

type Payload<T extends PayloadMap, K extends keyof T> = T[K] extends never ? [] : [payload: T[K]];

class Base<T extends PayloadMap = PayloadMap>  {
    emit<K extends keyof T>(type: K, ...payload: Payload<T, K>): Base<T> {
        return this;
    }
}

class Implementation<T extends PayloadMap = PayloadMap> extends Base<T> {
    constructor() {
        super();

        this.emit('hello', 'asdf'); // Argument of type '["asdf"]' is not assignable to parameter of type 'Payload<T, "hello">'.(2345)
        this.emit('none'); // Argument of type '[]' is not assignable to parameter of type 'Payload<T, "none">'.(2345)
    }
}

// all following `emit` calls are fine
let impl = {} as Implementation<{test: string} & PayloadMap>;
impl.emit('hello', 'asdf');
impl.emit('none');
impl.emit('test', 'asdf');

class GenericlessImplementation extends Base<{test: string} & PayloadMap> {
    constructor() {
        super();

        this.emit('hello', 'asdf');
        this.emit('none');
        this.emit('test', 'asdf');
    }
}

πŸ™ Actual behavior

This code example doesn't compile and I think it should as the generic is always constraint to PayloadMap.

πŸ™‚ Expected behavior

The example has compile errors because compiler is unable to find out that T is always compatible with PayloadMap.


Some context for the issue I'm dealing with - I'm trying to change typings to a base class we have in our library that is responsible for emitting events and acts as a base class for all other objects that need to emit events in the lib. We have an interface with eventName: PayloadType mapping - it basically defines all events that we emit and what payloads they have. This map is currently static but we want to make it generic so that users of the library can extend it and emit custom events. We need to support events with no payload - those are represneted by the never type. If the payload is never, emit function should be callable only with one argument, if the payload is any other type, the emit function has to be called with 2 arguments - that's what the Payload type does (and it works well - until we introduce generics).

I was looking at this bug report as well but it seems to be about something different, but I'm not 100% sure - #33369.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions