91 lines
2.7 KiB
TypeScript
91 lines
2.7 KiB
TypeScript
import { isRef } from 'vue';
|
|
import type { Ref, ShallowUnwrapRef } from 'vue';
|
|
|
|
export interface ExtendRefOptions<Unwrap extends boolean = boolean> {
|
|
/**
|
|
* Whether the extended properties are enumerable.
|
|
*
|
|
* @default false
|
|
*/
|
|
enumerable?: boolean;
|
|
|
|
/**
|
|
* Whether to unwrap (auto-`.value`) extended properties that are themselves refs.
|
|
*
|
|
* @default true
|
|
*/
|
|
unwrap?: Unwrap;
|
|
}
|
|
|
|
export type ExtendRefReturn<R extends Ref<unknown>, Extend extends object, Unwrap extends boolean>
|
|
= Unwrap extends false ? (R & ShallowUnwrapRef<Extend>) : (R & Extend);
|
|
|
|
/**
|
|
* @name extendRef
|
|
* @category Reactivity
|
|
* @description Attach extra (optionally reactive) attributes to a ref while keeping it a usable ref.
|
|
*
|
|
* @param {Ref<T>} ref The ref to extend
|
|
* @param {object} extend The properties to attach; ref-valued props are unwrapped by default
|
|
* @param {ExtendRefOptions} [options={}] `enumerable` (default `false`) and `unwrap` (default `true`)
|
|
* @returns {Ref<T> & Extend} The same ref instance, now carrying the extended properties
|
|
*
|
|
* @example
|
|
* const myRef = ref('content');
|
|
* const extended = extendRef(myRef, { foo: 'bar' });
|
|
* extended.value; // 'content'
|
|
* extended.foo; // 'bar'
|
|
*
|
|
* @example
|
|
* // reactive extension: unwrapped two-way by default
|
|
* const count = ref(0);
|
|
* const extended = extendRef(count, { double: computed(() => count.value * 2) });
|
|
* extended.double; // 0 (no .value needed)
|
|
*
|
|
* @example
|
|
* // keep refs as refs with unwrap: false
|
|
* const extended = extendRef(ref(0), { inner: ref(1) }, { unwrap: false });
|
|
* extended.inner.value; // 1
|
|
*
|
|
* @since 0.0.14
|
|
*/
|
|
export function extendRef<R extends Ref<unknown>, Extend extends object, Options extends ExtendRefOptions<false>>(ref: R, extend: Extend, options: Options): R & ShallowUnwrapRef<Extend>;
|
|
export function extendRef<R extends Ref<unknown>, Extend extends object, Options extends ExtendRefOptions>(ref: R, extend: Extend, options?: Options): R & Extend;
|
|
export function extendRef<R extends Ref<unknown>, Extend extends object>(
|
|
ref: R,
|
|
extend: Extend,
|
|
options: ExtendRefOptions = {},
|
|
): R & Extend {
|
|
const { enumerable = false, unwrap = true } = options;
|
|
|
|
for (const key in extend) {
|
|
if (key === 'value')
|
|
continue;
|
|
|
|
const value = extend[key];
|
|
|
|
if (unwrap && isRef(value)) {
|
|
Object.defineProperty(ref, key, {
|
|
get() {
|
|
return value.value;
|
|
},
|
|
set(v) {
|
|
value.value = v;
|
|
},
|
|
enumerable,
|
|
configurable: true,
|
|
});
|
|
}
|
|
else {
|
|
Object.defineProperty(ref, key, {
|
|
value,
|
|
enumerable,
|
|
configurable: true,
|
|
writable: true,
|
|
});
|
|
}
|
|
}
|
|
|
|
return ref as R & Extend;
|
|
}
|