Skip to content

Commit ce61b0c

Browse files
committed
feat: add props helper function
1 parent c635ed2 commit ce61b0c

File tree

4 files changed

+60
-17
lines changed

4 files changed

+60
-17
lines changed

src/helpers.ts

Lines 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

Lines 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

Lines 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

Lines 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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy