syncRef ​
Two-way refs synchronization.
Demo ​
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 ​
Show Type Declarations
typescript
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
Source ​
Contributors ​
Anthony Fu
Doctorwu
Mikhailov Nikita
Shean de Montigny-Desautels
Kylegl
zmtlwzy
Matias Capeletto
Changelog ​
v10.7.1
on 12/27/2023v10.7.0
on 12/5/2023v10.6.0
on 11/9/2023v10.4.0
on 8/25/2023v9.0.0-beta.2
on 7/24/2022