Skip to content

Commit 824ea5d

Browse files
rudyxurudyxu1102
rudyxu
authored andcommitted
docs: infer attrs rfc
1 parent cdee004 commit 824ea5d

File tree

1 file changed

+147
-0
lines changed

1 file changed

+147
-0
lines changed

active-rfcs/0000-infer-attrs.md

+147
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
- Start Date: 2023-01-01
2+
- Target Major Version: 3.x
3+
- Reference Issues: [vuejs/core#3452](https://github.com/vuejs/core/issues/3452), [vuejs/core#5423](https://github.com/vuejs/core/issues/5423),
4+
- Implementation PR: [vuejs/core#7444](https://github.com/vuejs/core/pull/7444)
5+
6+
# Summary
7+
Allow to infer `attrs` when passing type on the second param of `defineComponent` and `defineCustomElement`.
8+
And in the `setup-script`, passing generic type on the `useAttrs<T>` will infer `attrs` to `T`.
9+
10+
I already published an npm package named [vue-ts-utils](https://github.com/rudy-xhd/vue-ts-utils), so that you can use `defineComponent` to infer attrs in advance.
11+
12+
# Basic example
13+
14+
## Using `defineComponent`
15+
[TS Playground](https://www.typescriptlang.org/play?jsx=1#code/JYWwDg9gTgLgBAbzgEwKYDNgDtUGELgQ5bwC+c6UBcA5AG4CuqAtDAM7MMzAA2bNAWABQwgMZE28fODgBeFBmx4CkYjAAUCYXDhgqYNgC5E2nRQgRjAZRhRsAcwA0p0s6E6oqLGijqAlIikwq6IcACGMLZGgeFsoQBGYVDGWAwg8ahQcOSkfsJiEvDiMvIAPNJg5hCyCDQAjDTkiVA1deQA9AB8wkA)
16+
```tsx
17+
const Comp = defineComponent({
18+
props: {
19+
foo: String
20+
},
21+
render() {
22+
// number
23+
console.log(this.$attrs.bar)
24+
}
25+
}, { attrs: {} as { bar: number } })
26+
27+
const comp = <Comp foo={'str'} bar={1} />
28+
```
29+
30+
## Using `useAttrs<T>` in `script-setup`
31+
32+
```vue
33+
<script setup lang="ts">
34+
const attrs = useAttrs<{bar: number}>()
35+
</script>
36+
```
37+
38+
<details>
39+
<summary>Compiled Output</summary>
40+
41+
```js
42+
export default /*#__PURE__*/_defineComponent({
43+
setup(__props, { expose }) {
44+
expose();
45+
46+
const attrs = useAttrs<{ foo: number }>()
47+
48+
return { attrs, useAttrs, ref }
49+
}
50+
51+
}, { attrs: {} as { foo: number }})"
52+
```
53+
54+
</details>
55+
56+
57+
## Using `defineCustomElement`
58+
```tsx
59+
const Comp = defineCustomElement({
60+
props: {
61+
foo: String
62+
},
63+
render() {
64+
// number
65+
console.log(this.$attrs.bar)
66+
}
67+
}, { attrs: {} as { bar: number } })
68+
69+
```
70+
71+
# Motivation
72+
This proposal is mainly to infer `attrs` using `defineComponent`.
73+
74+
When using typescript in Vue3, the fallthrough attributes is unable to be used. It's not appropriate obviously that only one can be chosen from `typescript` and `the fallthrough attributes`. In most cases, we choose `typescript` and set attributes to `props` options instead of using the fallthrough attributes.
75+
76+
77+
# Detailed design
78+
79+
## `defineComponent`
80+
Due to typescript limitation from [microsoft/TypeScript#10571](https://github.com/microsoft/TypeScript/issues/10571), it's not possible to skip generics up to now in the `defineComponent` like below.
81+
```tsx
82+
// it's not work
83+
const Comp = defineComponent<Props, Attrs>({})
84+
```
85+
86+
There still has two ways to be chosen.
87+
88+
1. Defining the first param that already existing, just like [vuejs/rfcs#192](https://github.com/vuejs/rfcs/pull/192) did.
89+
```tsx
90+
const Comp = defineComponent({
91+
attrs: {} as { bar: number },
92+
props: {
93+
foo: String
94+
},
95+
render() {
96+
// number
97+
console.log(this.$attrs.bar)
98+
}
99+
})
100+
101+
const comp = <Comp foo={'str'} bar={1} />
102+
```
103+
2. Defining the second param as proposed.
104+
```tsx
105+
const Comp = defineComponent({
106+
props: {
107+
foo: String
108+
},
109+
render() {
110+
// number
111+
console.log(this.$attrs.bar)
112+
}
113+
}, { attrs: {} as { bar: number } })
114+
115+
const comp = <Comp foo={'str'} bar={1} />
116+
```
117+
118+
At last i chosen the second way that pass `attrs` type to the second params of `defineComponent`, because I think the code of the component should not be involved just for type definition.
119+
120+
121+
The following below is the design details.
122+
- `attrs` is inferred to `{ class: unknown; style: unknown }` when the value of the second param is `undefined`
123+
- `attrs` is lower priority than `props`.
124+
- [see for more detail cases](https://github.com/vuejs/core/pull/7444/files)
125+
126+
## `useAttrs<T>`
127+
In the `setup-script`, the generic type of `useAttrs` will compile to the second param of `defineComponent`.
128+
```ts
129+
export default /*#__PURE__*/_defineComponent({
130+
setup(__props, { expose }) {
131+
expose();
132+
133+
const attrs = useAttrs<{ foo: number }>()
134+
135+
return { attrs, useAttrs, ref }
136+
}
137+
138+
}, { attrs: {} as { foo: number }})"
139+
```
140+
141+
## `defineCustomElement`
142+
The type inferrence of `defineCustomElement` is the same as `defineComponent`.
143+
144+
145+
# Unresolved questions
146+
Naming suggestions or improvements on the API are welcome.
147+

0 commit comments

Comments
 (0)