3.9 KiB
3.9 KiB
category, related
| category | related |
|---|---|
| Reactivity | syncRefs |
syncRef
Two-way refs synchronization.
Usage
import { syncRef } from '@vueuse/core';
const a = ref('a');
const b = ref('b');
const stop = syncRef(a, b);
console.log(a.value); // a
b.value = 'foo';
console.log(a.value); // foo
a.value = 'bar';
console.log(b.value); // bar
One directional
import { syncRef } from '@vueuse/core';
const a = ref('a');
const b = ref('b');
const stop = syncRef(a, b, { direction: 'rtl' });
Custom Transform
import { syncRef } from '@vueuse/core';
const a = ref(10);
const b = ref(2);
const stop = syncRef(a, b, {
transform: {
ltr: (left) => left * 2,
rtl: (right) => right / 2,
},
});
console.log(b.value); // 20
b.value = 30;
console.log(a.value); // 15
Type Declarations
type Direction = 'ltr' | 'rtl' | 'both';
type SpecificFieldPartial<T, K extends keyof T> = Partial<Pick<T, K>> & Omit<T, K>;
/**
* A = B
*/
type Equal<A, B> = [A] extends [B] ? ([B] extends [A] ? true : false) : false;
/**
* A ∩ B ≠ ∅
*/
type IntersectButNotEqual<A, B> =
Equal<A, B> extends true ? false : A & B extends never ? false : true;
/**
* A ⊆ B
*/
type IncludeButNotEqual<A, B> = Equal<A, B> extends true ? false : A extends B ? true : false;
/**
* A ∩ B = ∅
*/
type NotIntersect<A, B> = Equal<A, B> extends true ? false : A & B extends never ? true : false;
interface EqualType<
D extends Direction,
L,
R,
O extends keyof Transform<L, R> = D extends 'both' ? 'ltr' | 'rtl' : D,
> {
transform?: SpecificFieldPartial<Pick<Transform<L, R>, O>, O>;
}
type StrictIncludeMap<
IncludeType extends 'LR' | 'RL',
D extends Exclude<Direction, 'both'>,
L,
R,
> = Equal<[IncludeType, D], ['LR', 'ltr']> & Equal<[IncludeType, D], ['RL', 'rtl']> extends true
? {
transform?: SpecificFieldPartial<Pick<Transform<L, R>, D>, D>;
}
: {
transform: Pick<Transform<L, R>, D>;
};
type StrictIncludeType<
IncludeType extends 'LR' | 'RL',
D extends Direction,
L,
R,
> = D extends 'both'
? {
transform: SpecificFieldPartial<Transform<L, R>, IncludeType extends 'LR' ? 'ltr' : 'rtl'>;
}
: D extends Exclude<Direction, 'both'>
? StrictIncludeMap<IncludeType, D, L, R>
: never;
type IntersectButNotEqualType<D extends Direction, L, R> = D extends 'both'
? {
transform: Transform<L, R>;
}
: D extends Exclude<Direction, 'both'>
? {
transform: Pick<Transform<L, R>, D>;
}
: never;
type NotIntersectType<D extends Direction, L, R> = IntersectButNotEqualType<D, L, R>;
interface Transform<L, R> {
ltr: (left: L) => R;
rtl: (right: R) => L;
}
type TransformType<D extends Direction, L, R> =
Equal<L, R> extends true
? EqualType<D, L, R>
: IncludeButNotEqual<L, R> extends true
? StrictIncludeType<'LR', D, L, R>
: IncludeButNotEqual<R, L> extends true
? StrictIncludeType<'RL', D, L, R>
: IntersectButNotEqual<L, R> extends true
? IntersectButNotEqualType<D, L, R>
: NotIntersect<L, R> extends true
? NotIntersectType<D, L, R>
: never;
export type SyncRefOptions<L, R, D extends Direction> = ConfigurableFlushSync & {
/**
* Watch deeply
*
* @default false
*/
deep?: boolean;
/**
* Sync values immediately
*
* @default true
*/
immediate?: boolean;
/**
* Direction of syncing. Value will be redefined if you define syncConvertors
*
* @default 'both'
*/
direction?: D;
} & TransformType<D, L, R>;
/**
* Two-way refs synchronization.
* From the set theory perspective to restrict the option's type
* Check in the following order:
* 1. L = R
* 2. L ∩ R ≠ ∅
* 3. L ⊆ R
* 4. L ∩ R = ∅
*/
export declare function syncRef<L, R, D extends Direction = 'both'>(
left: Ref<L>,
right: Ref<R>,
...[options]: Equal<L, R> extends true
? [options?: SyncRefOptions<L, R, D>]
: [options: SyncRefOptions<L, R, D>]
): () => void;