Skip to content

Cannot assign narrower EmitsOption type #2362

Closed
@sapphi-red

Description

Version

3.0.0

Reproduction link

https://codesandbox.io/s/vue3-emitsoption-covariance-x3okn

Steps to reproduce

  1. See App.vue
  2. Hover on context in Line 21 (const { emitA } = useAEmitter(context);).
  3. An error below is shown.
Argument of type 'SetupContext<{ a: () => true; b: () => true; }>' is not assignable to parameter of type 'SetupContext<{ a: () => boolean; }>'.
  Property 'b' is missing in type '{ a: () => boolean; }' but required in type '{ a: () => true; b: () => true; }'.

What is expected?

SetupContext<{ a: () => true, b: () => true }> is assignable to SetupContext<{ a: () => true }>.

What is actually happening?

SetupContext<{ a: () => true, b: () => true }> is not assignable to SetupContext<{ a: () => true }>.


type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never;

type EmitFn<Options, Event extends keyof Options = keyof Options> =
    Options extends any[]
        ? (event: Options[0], ...args: any[]) => void
        : {} extends Options
            ? (event: string, ...args: any[]) => void
            : UnionToIntersection<{
                [key in Event]:
                    Options[key] extends ((...args: infer Args) => any)
                        ? (event: key, ...args: Args) => void
                        : (event: key, ...args: any[]) => void;
            }[Event]>;

type SetupContext<E> = {
    emit: EmitFn<E>;
};

type SetupContextFix<E> = E extends any ? {
    emit: EmitFn<E>;
} : never;

let contextA!: SetupContext<{ a: () => true }>
let contextAB!: SetupContext<{ a: () => true, b: () => true }>

// here this is not assignable
contextA = contextAB

let eA!: {emit: EmitFn<{ a: () => true }>}
let eAB!: {emit: EmitFn<{ a: () => true, b: () => true }>}

// here this is assignable
eA = eAB

let contextFixA!: SetupContextFix<{ a: () => true }>
let contextFixAB!: SetupContextFix<{ a: () => true, b: () => true }>

// here this is assignable (I do not understand why this changes)
contextFixA = contextFixAB

typescript playground

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions