Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: split attrs and props mounting options #99

Merged
merged 3 commits into from
May 2, 2020

Conversation

cexbrayat
Copy link
Member

@cexbrayat cexbrayat commented Apr 28, 2020

This allows a slightly better type checking, even if defineComponent({ props: { a: String }}) sadly has $props typed as { a: string } & VNodeProps and VNodeProps allows anything. I'm not sure we can do much on VTU side for now.

See #90 for context

Copy link
Member

@pikax pikax left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we have a test with attrs?

@dobromir-hristov
Copy link
Contributor

I think mentally, users are probably used to having props and attrs separate. Most users would not know that for render funcs its the same prop.

I dont mind, the API change is small, feels clean and looks like it cleans up code as well :)

@lmiller1990
Copy link
Member

This seems fine to me (I didn't even know about the attrs API until recently - I never use that). This is also closer to the VTU for Vue 2 API, where we had both props and attrs, right?

Agree we should add a test for attrs. This would go in a new file, since each wrapper API has it's own file, and make it easy to find the relevant tests.

@@ -3,8 +3,3 @@ declare module '*.vue' {
import Vue from 'vue'
export default any
}

declare module 'vue' {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could use this:

declare module '*.vue' {
  import { ComponentOptions } from 'vue'
  var component: ComponentOptions
  export default component
}

Copy link
Member

@lmiller1990 lmiller1990 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code seems fine, can we have a few simple tests in a mountingOptions/attrs.spec.ts file

This allows a slightly better type checking, even if `defineComponent({ props: { a: String }})` sadly has `$props` typed as `{ a: string } & VNodeProps` and `VNodeProps` allows anything. I'm not sure we can do much on VTU side for now.
@cexbrayat
Copy link
Member Author

I pushed a few simple tests in a new commit and rebased on latest master. I kept the test in props.spec.ts that uses extra props as the behavior still exist, even if attrs should be preferred (until we find a way to properly type mount and forbid the "extra props as attrs" behavior).

})
})

test('assigns event listeners', async () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is technically the right way to attach a listener, not through attrs, even though they are identical as of now.

Copy link
Member Author

@cexbrayat cexbrayat May 2, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So your point is that we should keep the possibility of assigning extra props for this use-case?
There are several options:

  • do not allow it as it is in this PR, forcing the user to cast the props as any in the test, if he/she really wants to use props. I can change the test with a cast to let it in the current file.
  • allow it, but we lose a it of type safety as we can't make a difference between a badly written prop and an extra prop
  • allow it via some other possibility (mountingProps.extraProps ?) as it is not the most common use-case
    What do you think would be the most sound strategy?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So extra props would be attrs basically? If so, then I say just mention in the docs that people can use attrsfor that.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we can nudge the developers in the direction we feel makes more sense in the docs, either:

  • use attrs for extra props
  • or use props but cast with as any to indicate this is intentional.

props: { a: 'Hello', b: 2 }
})
// can't receive extra props
expectError(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would this error out for transparent components without props defined?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you give me an example of what you mean?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If a component has no props defined, and passes them down via $attrs.

const Component = {
   template: `<div><ChildComponent v-bind="$attrs"/></div>`
}
const wrapper = mount(Component, { props: { a:'a' } })

expect(wrapper.findComponent(ChildComponent).props('a')).toBe('a')

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, so yes: I expect this to error out if the props are not defined (as they end up with the never type). I think it makes sense to error out, as it is not the most common case, and let the developer use mount(Component, { props: { a:'a' } as any }) in that case. But I'm open to your suggestions if you think this is too constraint.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This wont error out for plain JS use right?

Erroring out is technically wrong, as the Vue API allows you to pass props to that kind of components, but as long as we state the reasoning behind this, should be fine :)

You are right, its not a common use case and having type safety for the 80% of people is better, we just need to make sure these little cases have workarounds for the more novice TS users out there.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes this is for TS developers only, JS will be fine, sorry if that wasn't clear :)

And even in TS it still works, it just forces the developers to cast the props if they want to use it with undeclared props.

IMO, TS developers will be happy to have intellisense/autocomplete/type-checking in tests, and won't be too lost if the compilation indicates that the props does not match the props of the component. But you're 100% right that we need to mention it the docs 👍

@cexbrayat
Copy link
Member Author

@dobromir-hristov I pushed a new commit to reflect our discussion with an example of an explicit cast: it won't get lost in the Github comments ;)

@lmiller1990 lmiller1990 merged commit d1a8c50 into vuejs:master May 2, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants