Subscribe on changes!

TypeScript does not infer SetupContext properly

avatar
Dec 7th 2020

Version

3.0.0

Reproduction link

https://codesandbox.io/s/vue3-example-hooks-ts-forked-uzeyf?file=/src/components/HelloWorldThatWorks.vue

Steps to reproduce

When the instance option emits is used with arrow-function validators (or in its simple array form), TypeScript fails to infer SetupContext<Record<string, any>> and instead infers SetupContext<{"update:modelValue": () => true}> (see the attached codesandbox example).

What is expected?

That I can just typehint { emit }: SetupContext in my composable.

What is actually happening?

I need to update type definition whenever I add an emits (or use "full" functions which is ugly).

(what you're looking for in the codesandbox is a TypeScript error. If you don't see one, wait a couple of seconds, usually it becomes visible after 15-20sec on the website - the context variable is underlined in red.)


I don't know if this is the right place to report. If this is not a bug but deliberate, please let me know. Thanks

avatar
Dec 7th 2020

@signor-pedro moved to the correct repository

avatar
Dec 8th 2020

Looks like this might be related, will investigate later https://github.com/vuejs/vue-next/issues/2474

avatar
Dec 8th 2020

I think this behavior is correct because this update:modelValue indicates that it does not receive any parameters. https://github.com/vuejs/rfcs/blob/master/active-rfcs/0030-emits-option.md#type-inference

  emits: {
    'update:modelValue': function works() { return true; },
  },

I think this should also infer SetupContext<{"update:modelValue": () => true}>.

Maybe #2362 is related?

  emits: {
    'update:modelValue'() { return true; },
  },

This may work for now. (though I think this also should infer SetupContext<{"update:modelValue": () => true}>)

avatar
Dec 9th 2020

@sapphi-red - if you are right and we should be inferring SetupContext<{"update:modelValue": () => true}>, how can I then type-hint the context properly?

All I wanted to do in my coposable is

function myFn({ emit }: SetupContext) {
   emit('sth', ...);
}

so that TypeScript (and in turn PHPStorm) infered the function signature for the emit function.

However, if I have to revisit the type hint every time I add a new emits, that sounds like I am not getting something about TypeScript... sorry, quite a TS newbie here 🤷

avatar
Dec 9th 2020

I think you should change it to SetupContext<any> if you want to be able to emit any event.

function myFn({ emit }: SetupContext<any>) {
   emit('sth', ...);
}

If you want to limit it to 'sth' event, do it like below.

function myFn({ emit }: SetupContext<{ sth: (params: any) => any }>) {
   emit('sth', ...);
}

I think there is no way to infer SetupContext type from the usage of emit.

avatar
Dec 22nd 2020

I think there is no way to infer SetupContext type from the usage of emit.

Yeah, I think there's not much to improve here as far as Vue's own types are concerned.

If you want to limit your function to certain event types, you will have to explicitly type them. The same is true for props, for example.

This is unrelated to #2474