Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit ce61b0c

Browse filesBrowse files
committed
feat: add props helper function
1 parent c635ed2 commit ce61b0c
Copy full SHA for ce61b0c

File tree

Expand file treeCollapse file tree

4 files changed

+60
-17
lines changed
Filter options
Expand file treeCollapse file tree

4 files changed

+60
-17
lines changed

‎src/helpers.ts

Copy file name to clipboardExpand all lines: src/helpers.ts
+15-2Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ComponentOptions, SetupContext, UnwrapRef } from 'vue'
1+
import { ComponentOptions, SetupContext, UnwrapRef, ComponentObjectPropsOptions, ExtractPropTypes } from 'vue'
22
import { Vue, VueBase, VueMixin } from './vue'
33

44
export function Options<V extends Vue>(
@@ -58,7 +58,9 @@ export type MixedVueBase<Mixins extends VueMixin[]> = Mixins extends (infer T)[]
5858
export function mixins<T extends VueMixin[]>(...Ctors: T): MixedVueBase<T>
5959
export function mixins(...Ctors: VueMixin[]): VueBase {
6060
return class MixedVue<Props> extends Vue<Props> {
61-
static __vccMixins = Ctors.map((Ctor) => Ctor.__vccOpts)
61+
static __vccExtend(options: ComponentOptions) {
62+
Ctors.forEach((Ctor) => Ctor.__vccExtend(options))
63+
}
6264

6365
constructor(props: Props, ctx: SetupContext) {
6466
super(props, ctx)
@@ -73,6 +75,17 @@ export function mixins(...Ctors: VueMixin[]): VueBase {
7375
}
7476
}
7577

78+
export function props<PropNames extends string, Props = Readonly<{ [key in PropNames]?: any }>>(propNames: PropNames[]): VueBase<Vue<Props> & Props>
79+
export function props<PropsOptions extends ComponentObjectPropsOptions, Props = Readonly<ExtractPropTypes<PropsOptions>>>(propsOptions: PropsOptions): VueBase<Vue<Props> & Props>
80+
export function props(propsOptions: string[] | ComponentObjectPropsOptions): VueBase {
81+
class PropsMixin<Props> extends Vue<Props> {
82+
static __vccExtend(options: ComponentOptions) {
83+
options.props = propsOptions
84+
}
85+
}
86+
return PropsMixin
87+
}
88+
7689
export function setup<R>(setupFn: () => R): UnwrapRef<R> {
7790
// Hack to delay the invocation of setup function.
7891
// Will be called after dealing with class properties.

‎src/index.ts

Copy file name to clipboardExpand all lines: src/index.ts
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
export { Vue, ClassComponentHooks } from './vue'
66

7-
export { Options, createDecorator, mixins, setup } from './helpers'
7+
export { Options, createDecorator, mixins, props, setup } from './helpers'
88

99
/**
1010
* Other types

‎src/vue.ts

Copy file name to clipboardExpand all lines: src/vue.ts
+12-13Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,13 @@ function defineProxy(proxy: any, key: string, target: any): void {
2929
})
3030
}
3131

32-
function getSuperOptions(Ctor: Function): ComponentOptions | undefined {
32+
function getSuper(Ctor: typeof VueImpl): typeof VueImpl | undefined {
3333
const superProto = Object.getPrototypeOf(Ctor.prototype)
3434
if (!superProto) {
3535
return undefined
3636
}
3737

38-
const Super = superProto.constructor as typeof Vue
39-
return Super.__vccOpts
38+
return superProto.constructor as typeof VueImpl
4039
}
4140

4241
export interface VueStatic {
@@ -52,7 +51,7 @@ export interface VueStatic {
5251
__vccDecorators?: ((options: ComponentOptions) => void)[]
5352

5453
/** @internal */
55-
__vccMixins?: ComponentOptions[]
54+
__vccExtend: ((options: ComponentOptions) => void)
5655

5756
/** @internal */
5857
__vccHooks: string[]
@@ -134,9 +133,6 @@ class VueImpl {
134133
/** @internal */
135134
static __vccDecorators?: ((options: ComponentOptions) => void)[]
136135

137-
/** @internal */
138-
static __vccMixins?: ComponentOptions[]
139-
140136
/** @internal */
141137
static __vccHooks = [
142138
'data',
@@ -155,6 +151,12 @@ class VueImpl {
155151
'serverPrefetch',
156152
]
157153

154+
/** @internal */
155+
static __vccExtend(options: ComponentOptions) {
156+
options.mixins = options.mixins || []
157+
options.mixins.push(this.__vccOpts)
158+
}
159+
158160
/** @internal */
159161
static get __vccOpts(): ComponentOptions {
160162
// Early return if `this` is base class as it does not have any options
@@ -175,12 +177,9 @@ class VueImpl {
175177
: {})
176178

177179
// Handle super class options
178-
options.extends = getSuperOptions(Ctor)
179-
180-
// Handle mixins
181-
const mixins = this.hasOwnProperty('__vccMixins') && this.__vccMixins
182-
if (mixins) {
183-
options.mixins = options.mixins ? options.mixins.concat(mixins) : mixins
180+
const Super = getSuper(Ctor)
181+
if (Super) {
182+
Super.__vccExtend(options)
184183
}
185184

186185
options.methods = { ...options.methods }

‎test/specs/test.spec.ts

Copy file name to clipboardExpand all lines: test/specs/test.spec.ts
+32-1Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import 'reflect-metadata'
22
import { h, resolveComponent, ref, onMounted, Ref, watch, toRef } from 'vue'
3-
import { Options, createDecorator, mixins, Vue, setup } from '../../src'
3+
import { Options, createDecorator, mixins, Vue, setup, props } from '../../src'
44
import { mount, unmount } from '../helpers'
55

66
describe('vue-class-component', () => {
@@ -378,6 +378,37 @@ describe('vue-class-component', () => {
378378
expect(root.valueB).toBe(456)
379379
})
380380

381+
it('props mixin: prop names', () => {
382+
const Props = props(['foo', 'bar'])
383+
384+
class App extends Props {
385+
baz = this.foo + this.bar
386+
}
387+
388+
const { root } = mount(App, { foo: 'Hello', bar: 'World' })
389+
expect(root.baz).toBe('HelloWorld')
390+
})
391+
392+
it('props mixin: props options object', () => {
393+
const Props = props({
394+
foo: {
395+
type: String,
396+
default: 'The answer is'
397+
},
398+
bar: {
399+
type: Number,
400+
required: true
401+
}
402+
})
403+
404+
class App extends Props {
405+
baz = this.foo + ': ' + this.bar
406+
}
407+
408+
const { root } = mount(App, { bar: 42 })
409+
expect(root.baz).toBe('The answer is: 42')
410+
})
411+
381412
it('uses composition functions', () => {
382413
function useCounter() {
383414
const count = ref(0)

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.