--- category: Reactivity related: syncRefs --- # syncRef Two-way refs synchronization. ## Usage ```ts 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 ```ts import { syncRef } from '@vueuse/core'; const a = ref('a'); const b = ref('b'); const stop = syncRef(a, b, { direction: 'rtl' }); ``` ### Custom Transform ```ts 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 ```ts type Direction = 'ltr' | 'rtl' | 'both'; type SpecificFieldPartial = Partial> & Omit; /** * A = B */ type Equal = [A] extends [B] ? ([B] extends [A] ? true : false) : false; /** * A ∩ B ≠ ∅ */ type IntersectButNotEqual = Equal extends true ? false : A & B extends never ? false : true; /** * A ⊆ B */ type IncludeButNotEqual = Equal extends true ? false : A extends B ? true : false; /** * A ∩ B = ∅ */ type NotIntersect = Equal extends true ? false : A & B extends never ? true : false; interface EqualType< D extends Direction, L, R, O extends keyof Transform = D extends 'both' ? 'ltr' | 'rtl' : D, > { transform?: SpecificFieldPartial, O>, O>; } type StrictIncludeMap< IncludeType extends 'LR' | 'RL', D extends Exclude, L, R, > = Equal<[IncludeType, D], ['LR', 'ltr']> & Equal<[IncludeType, D], ['RL', 'rtl']> extends true ? { transform?: SpecificFieldPartial, D>, D>; } : { transform: Pick, D>; }; type StrictIncludeType< IncludeType extends 'LR' | 'RL', D extends Direction, L, R, > = D extends 'both' ? { transform: SpecificFieldPartial, IncludeType extends 'LR' ? 'ltr' : 'rtl'>; } : D extends Exclude ? StrictIncludeMap : never; type IntersectButNotEqualType = D extends 'both' ? { transform: Transform; } : D extends Exclude ? { transform: Pick, D>; } : never; type NotIntersectType = IntersectButNotEqualType; interface Transform { ltr: (left: L) => R; rtl: (right: R) => L; } type TransformType = Equal extends true ? EqualType : IncludeButNotEqual extends true ? StrictIncludeType<'LR', D, L, R> : IncludeButNotEqual extends true ? StrictIncludeType<'RL', D, L, R> : IntersectButNotEqual extends true ? IntersectButNotEqualType : NotIntersect extends true ? NotIntersectType : never; export type SyncRefOptions = 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; /** * 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( left: Ref, right: Ref, ...[options]: Equal extends true ? [options?: SyncRefOptions] : [options: SyncRefOptions] ): () => void; ```