Skip to content

Commit bef8d36

Browse files
committed
fix: 修复 useWatch 回调参数类型推导 & v1.1.1 发版
- 新增 UnwrapRefSimple 工具类型,自动解包 Ref/ComputedRef - useWatch 回调参数类型由 T 改为 UnwrapRefSimple<T> - 当 source 为 useVRef(1) 时,回调参数自动推导为 number - 升级 runtime-core 版本 v1.1.0 -> v1.1.1 - 更新 CHANGELOG
1 parent 4d054e6 commit bef8d36

3 files changed

Lines changed: 54 additions & 6 deletions

File tree

packages/runtime-core/CHANGELOG.md

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [1.1.1] - 2026-04-26
9+
10+
### Fixed
11+
12+
- **修复 `useWatch` 回调参数类型推导**:当 `source` 为未解包的 `Ref` 时,回调参数能自动推导为解包后的类型
13+
14+
---
15+
16+
[1.1.1]: https://github.com/vureact-js/core/compare/v1.1.0...v1.1.1
17+
18+
---
19+
820
## [1.1.0] - 2026-04-17
921

1022
### Added
@@ -229,7 +241,8 @@ When releasing a new version:
229241
---
230242

231243
```
232-
[Unreleased]: https://github.com/vureact-js/core/compare/v1.1.0...HEAD
244+
[Unreleased]: https://github.com/vureact-js/core/compare/v1.1.1...HEAD
245+
[1.1.1]: https://github.com/vureact-js/core/compare/v1.1.0...v1.1.1
233246
[1.1.0]: https://github.com/vureact-js/core/compare/v1.0.1...v1.1.0
234247
[1.0.1]: https://github.com/vureact-js/core/compare/v1.0.0...v1.0.1
235248
[1.0.0]: https://github.com/vureact-js/core/compare/v1.0.0...HEAD

packages/runtime-core/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@vureact/runtime-core",
3-
"version": "1.1.0",
3+
"version": "1.1.1",
44
"type": "module",
55
"main": "./dist/cjs/runtime-core.js",
66
"module": "./dist/esm/runtime-core.esm.js",
@@ -93,4 +93,4 @@
9393
"react": ">=18.2.0",
9494
"react-dom": ">=18.2.0"
9595
}
96-
}
96+
}

packages/runtime-core/src/adapter-hooks/effect/useWatch.ts

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import { type DependencyList, RefObject, useCallback, useRef } from 'react';
22
import isEqual from 'react-fast-compare';
33
import { executeEffect } from '../shared/executeEffect';
44
import type { Destructor, FlushTiming, OnCleanup } from '../shared/types';
5+
import type { ComputedRef } from '../state/useComputed';
6+
import type { WrapRef } from '../state/useVRef';
57
import { unwrapRef } from '../state/useVRef';
68
import { useFlushEffect } from './shared';
79

@@ -28,13 +30,34 @@ type ResolvedWatchSource<T> = {
2830
isMultiSource: boolean;
2931
};
3032

33+
/**
34+
* 解包 ref/computed 类型,提取其内部值类型。
35+
* 如果 T 不是 ref/computed 类型,则返回 T 自身。
36+
*
37+
* - RefState<T> / WrapRef<T> → T
38+
* - ComputedRef<T> → T
39+
* - 其他类型 → T (原样)
40+
*/
41+
type UnwrapRefSimple<T> = T extends ComputedRef<infer U> ? U : T extends WrapRef<infer U> ? U : T;
42+
3143
/**
3244
* React adapter for Vue's watch API (manual dependencies mode).
45+
*
46+
* 当 source 传入一个 ref(如 useVRef 或 useComputed 的返回值)且
47+
* 没有手动通过 `.value` 解包时,回调参数会自动推导为解包后的值类型。
48+
*
49+
* @example
50+
*
51+
* const countRef = useVRef(1); // RefState<number>
52+
* useWatch(countRef, (newVal) => {
53+
* // newVal 被推导为 number(而非 RefState<number>)
54+
* });
55+
*
3356
* @see https://runtime.vureact.top/guide/hooks/watch.html
3457
*/
3558
export function useWatch<T>(
3659
source: WatchSource<T>,
37-
fn: WatchCallback<T, T>,
60+
fn: WatchCallback<UnwrapRefSimple<T>, UnwrapRefSimple<T>>,
3861
options?: WatchOptions,
3962
): WatchStopHandle {
4063
const callbackRef = useRef(fn);
@@ -90,7 +113,13 @@ export function useWatch<T>(
90113
initializedRef.current = true;
91114

92115
if (options?.immediate) {
93-
runAndRegisterCleanup(callbackRef.current, nextValue, undefined, cleanupRef, runCleanup);
116+
runAndRegisterCleanup(
117+
callbackRef.current,
118+
nextValue as any,
119+
undefined,
120+
cleanupRef,
121+
runCleanup,
122+
);
94123

95124
if (options?.once) {
96125
onceTriggeredRef.current = true;
@@ -119,7 +148,13 @@ export function useWatch<T>(
119148
return;
120149
}
121150

122-
runAndRegisterCleanup(callbackRef.current, nextValue, previousValue, cleanupRef, runCleanup);
151+
runAndRegisterCleanup(
152+
callbackRef.current,
153+
nextValue as any,
154+
previousValue as any,
155+
cleanupRef,
156+
runCleanup,
157+
);
123158

124159
currentValueRef.current = nextValue;
125160

0 commit comments

Comments
 (0)