vuejs / vue

This is the repo for Vue 2. For Vue 3, go to https://github.com/vuejs/core
http://v2.vuejs.org
MIT License
207.95k stars 33.68k forks source link

TypeScript: add Props type to component constructor #6901

Open wonderful-panda opened 7 years ago

wonderful-panda commented 7 years ago

What problem does this feature solve?

It would be useful if we can infer Props type from component (ExtendedVue).

For example, we can write type safe wrapper of CreateElement with it (or improve interface of CreateElement directly).

function renderComponent<Props>(
        h: CreateElement,
        component: ExtendedVue<Vue, {}, {}, {}, Props>,
        data: VNodeData & { props: Partial<Props> },
        children?: VNodeChildren): VNode {
  return h(component, data, children);
}

const MyComponent = Vue.extend({
  props: { foo: String },
  render(h) { return h("div", this.foo) };
});

const Parent = Vue.extend({
  render(h) {
    return renderComponent(h, MyComponent, { props: { foo: 0 } }); // error: type of property 'foo' are imcompatible
  }
});

What does the proposed API look like?

Now, ExtendedVue<Vue, {}, {}, {}, { foo: string }> and ExtendedVue<Vue, {}, {}, { foo: string }, {}> generate same type.

This means we can't determine Props type from ExtendedVue object.

I think, easiest (and most reasonable) way to achieve this is adding types to $props and $data

- export type CombinedVueInstance<Instance extends Vue, Data, Methods, Computed, Props> = Instance & Data & Methods & Computed & Props;
+ export type CombinedVueInstance<Instance extends Vue, Data, Methods, Computed, Props> = Instance & Data & Methods & Computed & Props & { $data: Data, $props: Props };
HerringtonDarkholme commented 7 years ago

Actually we can do better here. By changing Vue to a generic type constructor (with default so no breaking change), we can encode Vue.extend to return a constructor with $props and $data typed. Plus, typed JSX will be enabled.

But this will make our complex typing file more complicated. Let's first make Vue2.5 stable and wait for more feedback.

If you like this idea, please vote by emoji!

cc @ktsn @yyx990803 @octref @kaorun343

wonderful-panda commented 7 years ago

Sounds nice. Above all, it would be very nice if vue supports typed JSX by default. (I have a small library to add types to component for typed JSX. AAMOF, this issue comes from it.)

BTW, current typing loses the information about each props are required or optional, which is necessary for typed JSX.

HerringtonDarkholme commented 7 years ago

current typing loses the information about each props are required or optional

Fairly I don't think we can make a typing for current API, at least current TS' type system does not support it.

Example

blake-newman commented 7 years ago

I have been using library mentioned, I think first step we can do is make all props optional when using TSX with Partial, unless passing a declared interface.

It will then be an enhancement when TS does support it. I think we should also create a TS issue to make awareness of this requirement linking back to this issue.

I do believe we should support typed TSX out of the box with props inferred. Unfortunately but ultimately great Vue API also has more custom attributes to TSX such as scoped slots and events that we need to cater for. So interfaces will still be required as far as I can see. However where possible we should reduce the needed typing especially where duplication occurs, such as prop definitions.

wonderful-panda commented 7 years ago

How about an approach like below ?

image

(It works, but type definitions will become more complicated ...)

blake-newman commented 7 years ago

@wonderful-panda we could form requiredProps from props object no?

wonderful-panda commented 7 years ago

@blake-newman It may be impossible to obtain requiredProps from props at compile time.

In above example, type of repuiredProps is ("foo"|"bar")[]

blake-newman commented 7 years ago

Yes sorry forgot about that

JonasMatos0 commented 3 years ago

Hello,

What's the current state of this issue? I'm taking a look on these really old GFI tickets. I can try to help, just need some details about how to proceed.

Thanks in advance.