From 9a5355bd1b9db13e40f16ebfa4902f5cbfa03750 Mon Sep 17 00:00:00 2001 From: chiba Date: Sun, 29 Mar 2026 03:22:23 +0800 Subject: [PATCH 1/4] =?UTF-8?q?=E4=BF=AEbug=20useTypedEventValue=E7=8E=B0?= =?UTF-8?q?=E5=9C=A8ssr=E5=AE=89=E5=85=A8=E4=BA=86=20=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=E6=94=B6=E7=B4=A7UseTypedEventValueResult=E7=8E=B0=E5=9C=A8?= =?UTF-8?q?=E4=B8=8B=E6=B8=B8=E9=9C=80=E8=A6=81=E5=81=9Aundefined=E5=88=A4?= =?UTF-8?q?=E6=96=AD=E5=90=A6=E5=88=99=E4=BC=9A=E6=8E=A8=E5=AF=BC=E9=94=99?= =?UTF-8?q?=E8=AF=AF=20isFunction=E6=9B=B4=E7=8E=B0=E4=BB=A3=20=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E4=BA=86once()=E4=BC=9A=E6=BC=8F=E5=86=85=E7=B2=97?= =?UTF-8?q?=E5=86=85=E5=AD=98=E7=9A=84=E9=97=AE=E9=A2=98=20=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E4=BA=86=20const=20history:=20T[]=20=3D=20initialValu?= =?UTF-8?q?e=20=3F=20[initialValue]=20:=20[];=20=E5=AF=B9=200=20/=20false?= =?UTF-8?q?=20/=20''=20=E7=AD=89=20falsy=20=E5=80=BC=E5=88=A4=E6=96=AD?= =?UTF-8?q?=E9=94=99=E8=AF=AF=E7=9A=84=E9=97=AE=E9=A2=98=20=E6=8A=8A=20dis?= =?UTF-8?q?patch=20=E9=87=8C=E7=9A=84=20map=20=E6=94=B9=E6=88=90=E4=BA=86?= =?UTF-8?q?=20forEach=20=E7=8B=A0=E7=8B=A0=E6=94=B6=E7=B4=A7=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=EF=BC=8C=E7=B1=BB=E5=9E=8B=E5=87=A0=E4=B9=8E=E5=8F=AF?= =?UTF-8?q?=E6=8E=A8=E5=AF=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 10 +++-- pnpm-lock.yaml | 21 ++++------ pnpm-workspace.yaml | 3 ++ scripts/release.ts | 10 ----- src/index.ts | 71 +++++++++++++++++++------------ src/react.ts | 100 ++++++++++++++++++++++++++------------------ 6 files changed, 120 insertions(+), 95 deletions(-) delete mode 100644 scripts/release.ts diff --git a/package.json b/package.json index 2a57237..4c2467e 100644 --- a/package.json +++ b/package.json @@ -1,23 +1,25 @@ { "name": "@misaka17535/create-typed-event", - "version": "1.0.17", + "version": "2.0.0", "description": "Function-based and directive tiny typed event, with current value and optional react hook. Proven and well-tested in private projects. 全功能、函数式调用的微型事件库,可读取当前值且带有可选 react hook。在内部项目中久经考验。", "scripts": { "build": "tsup", + "prepare:dist": "tsx ./scripts/copyRequiredFilesToDist.ts", "test:link": "pnpm link ./dist", - "release": "tsx ./scripts/release.ts", - "postversion": "tsx ./scripts/copyRequiredFilesToDist.ts" + "release": "pnpm build && pnpm prepare:dist && np --contents=./dist --no-tests" }, "main": "index.js", "module": "index.mjs", "types": "index.d.ts", "exports": { ".": { + "types": "./index.d.ts", "import": "./index.mjs", "require": "./index.js", "default": "./index.js" }, "./react": { + "types": "./react.d.ts", "import": "./react.mjs", "require": "./react.js", "default": "./react.js" @@ -40,7 +42,7 @@ "publishConfig": { "access": "public" }, - "packageManager": "pnpm", + "packageManager": "pnpm@9.0.0", "devDependencies": { "@types/lodash-es": "^4.17.12", "@types/node": "^22.15.29", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3292b5d..7a8d577 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,9 +4,6 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false -overrides: - brace-expansion@>=2.0.0 <=2.0.1: '>=2.0.2' - importers: .: @@ -599,17 +596,15 @@ packages: atomically@2.0.3: resolution: {integrity: sha512-kU6FmrwZ3Lx7/7y3hPS5QnbJfaohcIul5fGqf7ok+4KklIEk9tJ0C2IQPdacSbVUWv6zVHXEBWoWd6NrVMT7Cw==} - balanced-match@3.0.1: - resolution: {integrity: sha512-vjtV3hiLqYDNRoiAv0zC4QaGAMPomEoq83PRmYIofPswwZurCeWR5LByXm7SyoL0Zh5+2z0+HC7jG8gSZJUh0w==} - engines: {node: '>= 16'} + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} boxen@8.0.1: resolution: {integrity: sha512-F3PH5k5juxom4xktynS7MoFY+NUWH5LC4CnH11YB8NPew+HLpmBLCybSAEyb2F+4pRXhuhWqFesoQd6DAyc2hw==} engines: {node: '>=18'} - brace-expansion@4.0.1: - resolution: {integrity: sha512-YClrbvTCXGe70pU2JiEiPLYXO9gQkyxYeKpJIQHVS/gOs6EWMQP2RYBwjFLNT322Ji8TOC3IMPfsYCedNpzKfA==} - engines: {node: '>= 18'} + brace-expansion@2.0.3: + resolution: {integrity: sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==} braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} @@ -2259,7 +2254,7 @@ snapshots: stubborn-fs: 1.2.5 when-exit: 2.1.4 - balanced-match@3.0.1: {} + balanced-match@1.0.2: {} boxen@8.0.1: dependencies: @@ -2272,9 +2267,9 @@ snapshots: widest-line: 5.0.0 wrap-ansi: 9.0.0 - brace-expansion@4.0.1: + brace-expansion@2.0.3: dependencies: - balanced-match: 3.0.1 + balanced-match: 1.0.2 braces@3.0.3: dependencies: @@ -2912,7 +2907,7 @@ snapshots: minimatch@9.0.5: dependencies: - brace-expansion: 4.0.1 + brace-expansion: 2.0.3 minimist@1.2.8: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index e96b9a6..2e3142e 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,3 +1,6 @@ +packages: + - '.' + onlyBuiltDependencies: - esbuild diff --git a/scripts/release.ts b/scripts/release.ts deleted file mode 100644 index 6bf1aa0..0000000 --- a/scripts/release.ts +++ /dev/null @@ -1,10 +0,0 @@ -import {execSync} from 'child_process'; - -const main = async () => { - console.log('构建...'); - execSync('pnpm tsup', {stdio: 'inherit'}); - console.log('发布...'); - execSync('pnpm np --contents=./dist --no-tests', {stdio: 'inherit'}); -}; - -main(); diff --git a/src/index.ts b/src/index.ts index aa62f4c..fd94877 100644 --- a/src/index.ts +++ b/src/index.ts @@ -35,30 +35,49 @@ * @member value 获取最新的值。 */ -type cb = (payload: T) => void; +export type TypedEventCallback = (payload: T) => void; -export const createTypedEvent = ({ - dispatchLastValueOnSubscribe = false, - initialValue, - }: { +export interface TypedEvent { + sub: (cb: TypedEventCallback) => () => void; + unsub: (cb: TypedEventCallback) => void; + dispatch: (payload: T) => void; + once: (cb: TypedEventCallback) => () => void; + readonly value: T | undefined; +} + +export interface InitializedTypedEvent extends TypedEvent { + readonly value: T; +} + +export interface CreateTypedEventOptions { dispatchLastValueOnSubscribe?: boolean; initialValue?: T; -} = {}) => { - const history: T[] = initialValue ? [initialValue] : []; - const cbs: Array> = []; - const instance: { - sub: (cb: cb) => () => void; - unsub: (cb: cb) => void; - dispatch: (payload: T) => void; - once: (cb: cb) => () => void; - readonly value: T; - } = { - sub: (cb: cb) => { +} + +export interface CreateInitializedTypedEventOptions extends CreateTypedEventOptions { + initialValue: T; +} + +export function createTypedEvent(options: CreateInitializedTypedEventOptions): InitializedTypedEvent; +export function createTypedEvent(options?: CreateTypedEventOptions): TypedEvent; +export function createTypedEvent(options: CreateTypedEventOptions = {}): TypedEvent { + const { + dispatchLastValueOnSubscribe = false, + initialValue, + } = options; + const hasInitialValue = Object.prototype.hasOwnProperty.call(options, 'initialValue'); + const history: T[] = []; + if (hasInitialValue) { + history.push(initialValue as T); + } + const cbs: Array> = []; + const instance: TypedEvent = { + sub: (cb: TypedEventCallback) => { cbs.push(cb); if (dispatchLastValueOnSubscribe && history.length > 0) cb(history[0]); return () => instance.unsub(cb); }, - unsub: (cb: cb) => { + unsub: (cb: TypedEventCallback) => { const index = cbs.indexOf(cb); if (index === -1) return; cbs.splice(index, 1); @@ -67,14 +86,15 @@ export const createTypedEvent = ({ // history update must go before callbacks, // to ensure callbacks can get the latest value history[0] = payload; - cbs.map(v => v(payload)); + cbs.forEach(v => v(payload)); }, - once: (cb: cb) => { - instance.sub((arg: T) => { + once: (cb: TypedEventCallback) => { + const wrappedCb = (arg: T) => { cb(arg); - instance.unsub(cb); - }); - return () => instance.unsub(cb); + instance.unsub(wrappedCb); + }; + instance.sub(wrappedCb); + return () => instance.unsub(wrappedCb); }, get value() { return history[0]; @@ -84,7 +104,4 @@ export const createTypedEvent = ({ }, }; return instance; -}; - - -export type TypedEvent = ReturnType>; +} diff --git a/src/react.ts b/src/react.ts index 17567f7..3172115 100644 --- a/src/react.ts +++ b/src/react.ts @@ -1,36 +1,45 @@ -import {createTypedEvent, TypedEvent} from "./index"; -import {Dispatch, SetStateAction, useCallback, useEffect, useMemo, useRef, useState} from "react"; +import {createTypedEvent, CreateTypedEventOptions, TypedEvent} from "./index"; +import {Dispatch, SetStateAction, useCallback, useMemo, useRef, useState, useSyncExternalStore} from "react"; -const isFunction = (obj: any): obj is (...args: any) => any => { - return !!(obj && obj.constructor && obj.call && obj.apply); +export type ReadonlyRefObject = { + readonly current: T; +}; + +export type UseTypedEventValueResult = [ + T | undefined, + TypedEvent["dispatch"], + ReadonlyRefObject, +]; + +const isFunction = (value: SetStateAction): value is (prevState: T) => T => { + return typeof value === "function"; }; // 临时直接嵌入 useHybridState 的实现,后续发包再改 -export const useHybridState: { - (initialValue: T): [ - T, - Dispatch>, - { - readonly current: T; - }, - ]; - (): [ - T | undefined, - Dispatch>, - { - readonly current: T | undefined; - }, - ]; -} = (initialValue?: T) => { +export function useHybridState(initialValue: T): [ + T, + Dispatch>, + ReadonlyRefObject, +]; +export function useHybridState(): [ + T | undefined, + Dispatch>, + ReadonlyRefObject, +]; +export function useHybridState(initialValue?: T): [ + T | undefined, + Dispatch>, + ReadonlyRefObject, +] { const [state, setState] = useState(initialValue); const ref = useRef(initialValue); - const set = useCallback((val: T) => { - if (isFunction(val)) { - ref.current = val(ref.current); + const set = useCallback((value: SetStateAction) => { + if (isFunction(value)) { + ref.current = value(ref.current); } else { - ref.current = val; + ref.current = value; } - setState(val); + setState(value); }, []); const refBehindProxy = useMemo( () => @@ -43,17 +52,12 @@ export const useHybridState: { }), [], ); - return [state, set, refBehindProxy] as [ - typeof state, - Dispatch>, - { - readonly current: T; - }, - ]; -}; + return [state, set, refBehindProxy]; +} -export const createTypedEventMemorized: typeof createTypedEvent = (...args) => - useMemo(() => createTypedEvent(...args), []); +export function createTypedEventMemorized(options?: CreateTypedEventOptions): TypedEvent { + return useMemo(() => createTypedEvent(options), []); +} /** * @description @@ -61,10 +65,24 @@ export const createTypedEventMemorized: typeof createTypedEvent = (...args) => * @example * const [marketPrice, setMarketPrice, marketPriceRef] = useTypedEventValue(marketPriceUpdateEvent); */ -export const useTypedEventValue = (event: TypedEvent) => { - const [value, setValue, valueRef] = useHybridState(event.value); - useEffect(() => { - return event.sub(setValue); - }, []); - return [value, event.dispatch, valueRef] as const; +export const useTypedEventValue = (event: TypedEvent): UseTypedEventValueResult => { + const value = useSyncExternalStore( + useCallback((onStoreChange) => event.sub(() => onStoreChange()), [event]), + useCallback(() => event.value, [event]), + useCallback(() => event.value, [event]), + ); + const valueRef = useRef(value); + valueRef.current = value; + const refBehindProxy = useMemo( + () => + new Proxy(valueRef, { + set: () => { + throw new Error( + "Do not change value of this ref, it's readonly. Instead, use the set method.", + ); + }, + }), + [], + ); + return [value, event.dispatch, refBehindProxy]; }; From 1bb7ccdae6effee6553081cef07817e97d5e1a3d Mon Sep 17 00:00:00 2001 From: chiba Date: Sun, 29 Mar 2026 20:03:48 +0800 Subject: [PATCH 2/4] =?UTF-8?q?=E4=BF=AEbug=20=E5=9B=9E=E6=BB=9A=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=E7=B3=BB=E7=BB=9F=EF=BC=8C=E5=8F=AA=E4=BF=9D=E7=95=99?= =?UTF-8?q?isFunc=E6=96=B0=E5=86=99=E6=B3=95=EF=BC=8C=E5=8F=AA=E4=BF=9D?= =?UTF-8?q?=E7=95=99once=E4=BF=AE=E5=A4=8D=20=E5=8F=AA=E4=BF=9D=E7=95=99?= =?UTF-8?q?=E6=9B=B4=E5=AE=BD=E6=9D=BE=E7=B1=BB=E5=9E=8B=E4=BD=86ssr?= =?UTF-8?q?=E5=AE=89=E5=85=A8=E7=9A=84useTypedEventValue=E5=8C=85=E8=A3=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/index.ts | 62 ++++++++++++++++-------------------------- src/react.ts | 76 +++++++++++++++++++++++++--------------------------- 2 files changed, 59 insertions(+), 79 deletions(-) diff --git a/src/index.ts b/src/index.ts index fd94877..0685a9a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -35,49 +35,30 @@ * @member value 获取最新的值。 */ -export type TypedEventCallback = (payload: T) => void; +type cb = (payload: T) => void; -export interface TypedEvent { - sub: (cb: TypedEventCallback) => () => void; - unsub: (cb: TypedEventCallback) => void; - dispatch: (payload: T) => void; - once: (cb: TypedEventCallback) => () => void; - readonly value: T | undefined; -} - -export interface InitializedTypedEvent extends TypedEvent { - readonly value: T; -} - -export interface CreateTypedEventOptions { +export const createTypedEvent = ({ + dispatchLastValueOnSubscribe = false, + initialValue, + }: { dispatchLastValueOnSubscribe?: boolean; initialValue?: T; -} - -export interface CreateInitializedTypedEventOptions extends CreateTypedEventOptions { - initialValue: T; -} - -export function createTypedEvent(options: CreateInitializedTypedEventOptions): InitializedTypedEvent; -export function createTypedEvent(options?: CreateTypedEventOptions): TypedEvent; -export function createTypedEvent(options: CreateTypedEventOptions = {}): TypedEvent { - const { - dispatchLastValueOnSubscribe = false, - initialValue, - } = options; - const hasInitialValue = Object.prototype.hasOwnProperty.call(options, 'initialValue'); - const history: T[] = []; - if (hasInitialValue) { - history.push(initialValue as T); - } - const cbs: Array> = []; - const instance: TypedEvent = { - sub: (cb: TypedEventCallback) => { +} = {}) => { + const history: T[] = initialValue ? [initialValue] : []; + const cbs: Array> = []; + const instance: { + sub: (cb: cb) => () => void; + unsub: (cb: cb) => void; + dispatch: (payload: T) => void; + once: (cb: cb) => () => void; + readonly value: T; + } = { + sub: (cb: cb) => { cbs.push(cb); if (dispatchLastValueOnSubscribe && history.length > 0) cb(history[0]); return () => instance.unsub(cb); }, - unsub: (cb: TypedEventCallback) => { + unsub: (cb: cb) => { const index = cbs.indexOf(cb); if (index === -1) return; cbs.splice(index, 1); @@ -86,9 +67,9 @@ export function createTypedEvent(options: CreateTypedEventOptions = // history update must go before callbacks, // to ensure callbacks can get the latest value history[0] = payload; - cbs.forEach(v => v(payload)); + cbs.map(v => v(payload)); }, - once: (cb: TypedEventCallback) => { + once: (cb: cb) => { const wrappedCb = (arg: T) => { cb(arg); instance.unsub(wrappedCb); @@ -104,4 +85,7 @@ export function createTypedEvent(options: CreateTypedEventOptions = }, }; return instance; -} +}; + + +export type TypedEvent = ReturnType>; diff --git a/src/react.ts b/src/react.ts index 3172115..7b358b2 100644 --- a/src/react.ts +++ b/src/react.ts @@ -1,45 +1,36 @@ -import {createTypedEvent, CreateTypedEventOptions, TypedEvent} from "./index"; +import {createTypedEvent, TypedEvent} from "./index"; import {Dispatch, SetStateAction, useCallback, useMemo, useRef, useState, useSyncExternalStore} from "react"; - -export type ReadonlyRefObject = { - readonly current: T; -}; - -export type UseTypedEventValueResult = [ - T | undefined, - TypedEvent["dispatch"], - ReadonlyRefObject, -]; - -const isFunction = (value: SetStateAction): value is (prevState: T) => T => { +// +const isFunction = (value: any): value is (...args: any) => any => { return typeof value === "function"; }; // 临时直接嵌入 useHybridState 的实现,后续发包再改 -export function useHybridState(initialValue: T): [ - T, - Dispatch>, - ReadonlyRefObject, -]; -export function useHybridState(): [ - T | undefined, - Dispatch>, - ReadonlyRefObject, -]; -export function useHybridState(initialValue?: T): [ - T | undefined, - Dispatch>, - ReadonlyRefObject, -] { +export const useHybridState: { + (initialValue: T): [ + T, + Dispatch>, + { + readonly current: T; + }, + ]; + (): [ + T | undefined, + Dispatch>, + { + readonly current: T | undefined; + }, + ]; +} = (initialValue?: T) => { const [state, setState] = useState(initialValue); const ref = useRef(initialValue); - const set = useCallback((value: SetStateAction) => { - if (isFunction(value)) { - ref.current = value(ref.current); + const set = useCallback((val: T) => { + if (isFunction(val)) { + ref.current = val(ref.current); } else { - ref.current = value; + ref.current = val; } - setState(value); + setState(val); }, []); const refBehindProxy = useMemo( () => @@ -52,12 +43,17 @@ export function useHybridState(initialValue?: T): [ }), [], ); - return [state, set, refBehindProxy]; -} + return [state, set, refBehindProxy] as [ + typeof state, + Dispatch>, + { + readonly current: T; + }, + ]; +}; -export function createTypedEventMemorized(options?: CreateTypedEventOptions): TypedEvent { - return useMemo(() => createTypedEvent(options), []); -} +export const createTypedEventMemorized: typeof createTypedEvent = (...args) => + useMemo(() => createTypedEvent(...args), []); /** * @description @@ -65,7 +61,7 @@ export function createTypedEventMemorized(options?: CreateTypedEventOp * @example * const [marketPrice, setMarketPrice, marketPriceRef] = useTypedEventValue(marketPriceUpdateEvent); */ -export const useTypedEventValue = (event: TypedEvent): UseTypedEventValueResult => { +export const useTypedEventValue = (event: TypedEvent) => { const value = useSyncExternalStore( useCallback((onStoreChange) => event.sub(() => onStoreChange()), [event]), useCallback(() => event.value, [event]), @@ -84,5 +80,5 @@ export const useTypedEventValue = (event: TypedEvent): UseTypedEven }), [], ); - return [value, event.dispatch, refBehindProxy]; + return [value, event.dispatch, refBehindProxy] as const; }; From 7c7125bcbdd650ff330ed620427203dd6c4d73a0 Mon Sep 17 00:00:00 2001 From: chiba Date: Sun, 29 Mar 2026 20:18:09 +0800 Subject: [PATCH 3/4] =?UTF-8?q?=E4=BD=BF=E7=94=A8use-sync-external-store/s?= =?UTF-8?q?him=E4=BB=A3=E6=9B=BFreact=E5=AF=BC=E5=87=BA=E4=BB=A5=E9=80=82?= =?UTF-8?q?=E9=85=8Dreact16=E7=9A=84=E5=9F=BA=E7=A1=80=E7=9B=AE=E6=A0=87?= =?UTF-8?q?=EF=BC=8C=E5=B0=86=E7=89=88=E6=9C=AC=E5=8F=B7=E6=81=A2=E5=A4=8D?= =?UTF-8?q?=E8=A1=A5=E4=B8=81=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 8 +++++--- pnpm-lock.yaml | 12 ++++++++++++ src/react.ts | 7 ++++--- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 4c2467e..61aedd6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@misaka17535/create-typed-event", - "version": "2.0.0", + "version": "1.0.18", "description": "Function-based and directive tiny typed event, with current value and optional react hook. Proven and well-tested in private projects. 全功能、函数式调用的微型事件库,可读取当前值且带有可选 react hook。在内部项目中久经考验。", "scripts": { "build": "tsup", @@ -57,10 +57,12 @@ "react": "^19.1.0", "tsup": "^8.5.0", "tsx": "^4.19.4", - "typescript": "^5.8.3" + "typescript": "^5.8.3", + "use-sync-external-store": "^1.6.0" }, "peerDependencies": { - "react": ">=16" + "react": ">=16", + "use-sync-external-store": ">=1" }, "peerDependenciesMeta": { "react": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7a8d577..2333611 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -50,6 +50,9 @@ importers: typescript: specifier: ^5.8.3 version: 5.8.3 + use-sync-external-store: + specifier: ^1.6.0 + version: 1.6.0(react@19.1.0) packages: @@ -1799,6 +1802,11 @@ packages: resolution: {integrity: sha512-+dwUY4L35XFYEzE+OAL3sarJdUioVovq+8f7lcIJ7wnmnYQV5UD1Y/lcwaMSyaQ6Bj3JMj1XSTjZbNLHn/19yA==} engines: {node: '>=18'} + use-sync-external-store@1.6.0: + resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + validate-npm-package-license@3.0.4: resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} @@ -3477,6 +3485,10 @@ snapshots: semver: 7.7.2 xdg-basedir: 5.1.0 + use-sync-external-store@1.6.0(react@19.1.0): + dependencies: + react: 19.1.0 + validate-npm-package-license@3.0.4: dependencies: spdx-correct: 3.2.0 diff --git a/src/react.ts b/src/react.ts index 7b358b2..9293dba 100644 --- a/src/react.ts +++ b/src/react.ts @@ -1,6 +1,7 @@ import {createTypedEvent, TypedEvent} from "./index"; -import {Dispatch, SetStateAction, useCallback, useMemo, useRef, useState, useSyncExternalStore} from "react"; -// +import {Dispatch, SetStateAction, useCallback, useMemo, useRef, useState} from "react"; +import {useSyncExternalStore} from "use-sync-external-store/shim"; + const isFunction = (value: any): value is (...args: any) => any => { return typeof value === "function"; }; @@ -63,7 +64,7 @@ export const createTypedEventMemorized: typeof createTypedEvent = (...args) => */ export const useTypedEventValue = (event: TypedEvent) => { const value = useSyncExternalStore( - useCallback((onStoreChange) => event.sub(() => onStoreChange()), [event]), + useCallback((onStoreChange: () => void) => event.sub(() => onStoreChange()), [event]), useCallback(() => event.value, [event]), useCallback(() => event.value, [event]), ); From e806c2b99e15566f605a3e1aaa732e3314bc9e06 Mon Sep 17 00:00:00 2001 From: chiba Date: Sun, 29 Mar 2026 20:19:31 +0800 Subject: [PATCH 4/4] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E9=9D=9E=E8=BF=90?= =?UTF-8?q?=E8=A1=8C=E6=97=B6=E7=B1=BB=E5=9E=8B=E5=A3=B0=E6=98=8E=E9=81=BF?= =?UTF-8?q?=E5=85=8D=E7=B1=BB=E5=9E=8B=E9=94=99=E8=AF=AFuse-sync-external-?= =?UTF-8?q?store-shim.d.ts?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- use-sync-external-store-shim.d.ts | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 use-sync-external-store-shim.d.ts diff --git a/use-sync-external-store-shim.d.ts b/use-sync-external-store-shim.d.ts new file mode 100644 index 0000000..719c4d3 --- /dev/null +++ b/use-sync-external-store-shim.d.ts @@ -0,0 +1,7 @@ +declare module "use-sync-external-store/shim" { + export function useSyncExternalStore( + subscribe: (onStoreChange: () => void) => () => void, + getSnapshot: () => Snapshot, + getServerSnapshot?: () => Snapshot, + ): Snapshot; +}