Skip to content

Commit df2d534

Browse files
committed
feat: add compiler safe API for mutables
1 parent a2b44cc commit df2d534

File tree

2 files changed

+44
-4
lines changed

2 files changed

+44
-4
lines changed

packages/react-native-reanimated/src/commonTypes.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,15 @@ export interface StyleProps extends ViewStyle, TextStyle {
1515
*/
1616
export interface SharedValue<Value = unknown> {
1717
value: Value;
18+
get(): Value;
19+
set(value: Value): void;
1820
addListener: (listenerID: number, listener: (value: Value) => void) => void;
1921
removeListener: (listenerID: number) => void;
2022
modify: (
2123
modifier?: <T extends Value>(value: T) => T,
2224
forceUpdate?: boolean
2325
) => void;
2426
}
25-
2627
export interface Mutable<Value = unknown> extends SharedValue<Value> {
2728
_isReanimatedSharedValue: true;
2829
_animation?: AnimationObject<Value> | null; // only in Native

packages/react-native-reanimated/src/mutables.ts

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,39 @@ const SHOULD_BE_USE_WEB = shouldBeUseWeb();
1010

1111
type Listener<Value> = (newValue: Value) => void;
1212

13+
type PartialMutable<Value> = Omit<Mutable<Value>, '_value' | 'get' | 'set'>;
14+
15+
/**
16+
* Adds `get` and `set` methods to the mutable object to handle access to `value` property.
17+
*
18+
* React Compiler disallows modifying return values of hooks. Even though assignment to
19+
* `value` is a setter invocation, Compiler's static analysis doesn't detect it.
20+
* That's why we provide a second API for users using the Compiler.
21+
*/
22+
function addCompilerSafeGetAndSet<Value>(mutable: Mutable<Value>): void {
23+
'worklet';
24+
Object.defineProperties(mutable, {
25+
get: {
26+
value() {
27+
return mutable.value;
28+
},
29+
configurable: false,
30+
enumerable: false,
31+
},
32+
set: {
33+
value(newValue: Value | ((value: Value) => Value)) {
34+
if (typeof newValue === 'function') {
35+
mutable.value = (newValue as (value: Value) => Value)(mutable.value);
36+
} else {
37+
mutable.value = newValue;
38+
}
39+
},
40+
configurable: false,
41+
enumerable: false,
42+
},
43+
});
44+
}
45+
1346
export function makeMutableUI<Value>(initial: Value): Mutable<Value> {
1447
'worklet';
1548
const listeners = new Map<number, Listener<Value>>();
@@ -39,7 +72,7 @@ export function makeMutableUI<Value>(initial: Value): Mutable<Value> {
3972

4073
_animation: null,
4174
_isReanimatedSharedValue: true,
42-
} as Mutable<Value>;
75+
} as PartialMutable<Value> as Mutable<Value>;
4376

4477
/*
4578
* _value prop should only be accessed by the valueSetter implementation
@@ -61,6 +94,8 @@ export function makeMutableUI<Value>(initial: Value): Mutable<Value> {
6194
enumerable: false,
6295
});
6396

97+
addCompilerSafeGetAndSet(mutable);
98+
6499
return mutable;
65100
}
66101

@@ -102,7 +137,7 @@ function makeMutableNative<Value>(initial: Value): Mutable<Value> {
102137
},
103138

104139
_isReanimatedSharedValue: true,
105-
} as Omit<Mutable<Value>, '_value'> as Mutable<Value>;
140+
} as PartialMutable<Value> as Mutable<Value>;
106141

107142
Object.defineProperty(mutable, '_value', {
108143
// This way of defining the property makes it hidden for
@@ -122,6 +157,8 @@ function makeMutableNative<Value>(initial: Value): Mutable<Value> {
122157
enumerable: false,
123158
});
124159

160+
addCompilerSafeGetAndSet(mutable);
161+
125162
shareableMappingCache.set(mutable, handle);
126163
return mutable;
127164
}
@@ -153,7 +190,7 @@ function makeMutableWeb<Value>(initial: Value): Mutable<Value> {
153190
},
154191

155192
_isReanimatedSharedValue: true,
156-
} as Omit<Mutable<Value>, '_value'> as Mutable<Value>;
193+
} as PartialMutable<Value> as Mutable<Value>;
157194

158195
Object.defineProperty(mutable, '_value', {
159196
get(): Value {
@@ -169,6 +206,8 @@ function makeMutableWeb<Value>(initial: Value): Mutable<Value> {
169206
enumerable: false,
170207
});
171208

209+
addCompilerSafeGetAndSet(mutable);
210+
172211
return mutable;
173212
}
174213

0 commit comments

Comments
 (0)