Skip to content

Commit 367c457

Browse files
committed
fix(types): allow using interface for replicant type
1 parent 8235937 commit 367c457

File tree

4 files changed

+58
-19
lines changed

4 files changed

+58
-19
lines changed

package-lock.json

Lines changed: 18 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,8 @@
7777
"dependencies": {
7878
"@nodecg/types": "^2.1.8",
7979
"klona": "^2.0.6",
80-
"tslib": "^2.0.0"
80+
"tslib": "^2.0.0",
81+
"type-fest": "^4.13.1"
8182
},
8283
"devDependencies": {
8384
"@hoishin/prettierrc": "2.1.1",

src/use-replicant.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
1-
import { useEffect, useMemo, useState } from "react";
1+
import { useCallback, useEffect, useMemo, useState } from "react";
22
import { klona as clone } from "klona/json";
3-
4-
type JsonValue = boolean | number | string | null;
5-
6-
type Json = JsonValue | JsonValue[] | { [key: string]: Json } | Json[];
3+
import { Jsonify } from "type-fest";
74

85
export type UseReplicantOptions<T> = {
96
defaultValue?: T;
@@ -19,7 +16,7 @@ export type UseReplicantOptions<T> = {
1916
* @param initialValue Initial value to pass to `useState` function
2017
* @param options Options object. Currently supports the optional `namespace` option
2118
*/
22-
export const useReplicant = <T extends Json>(
19+
export const useReplicant = <V, T = Jsonify<V>>(
2320
replicantName: string,
2421
{ bundle, defaultValue, persistent }: UseReplicantOptions<T> = {},
2522
) => {
@@ -50,14 +47,17 @@ export const useReplicant = <T extends Json>(
5047
};
5148
}, [replicant]);
5249

53-
return [
54-
value,
50+
const updateValue = useCallback(
5551
(newValue: T | ((oldValue?: T) => void)) => {
5652
if (typeof newValue === "function") {
57-
newValue(replicant.value);
53+
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
54+
(newValue as any)(replicant.value);
5855
} else {
5956
replicant.value = newValue;
6057
}
6158
},
62-
] as const;
59+
[replicant],
60+
);
61+
62+
return [value, updateValue] as const;
6363
};

tests/use-replicant.spec.tsx

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
import { EventEmitter } from "events";
66

7-
import React from "react";
7+
import React, { useEffect } from "react";
88
import { render, act, fireEvent } from "@testing-library/react";
99
import type { RenderResult } from "@testing-library/react";
1010

@@ -78,6 +78,33 @@ type RunnerNameReplicant = {
7878
};
7979
};
8080

81+
interface DummyTypeInterface {
82+
runner: {
83+
name: string;
84+
};
85+
}
86+
87+
interface DummyTypeInterface2 {
88+
foo: Date;
89+
bar: () => number;
90+
}
91+
92+
export const DummyComponent = () => {
93+
const [_, setDummy] = useReplicant<DummyTypeInterface>("foo");
94+
useEffect(() => {
95+
setDummy({ runner: { name: "bar" } });
96+
setDummy((oldValue) => {
97+
if (oldValue) {
98+
oldValue.runner.name += "name";
99+
}
100+
});
101+
}, [setDummy]);
102+
103+
useReplicant<DummyTypeInterface2>("bar");
104+
105+
return null;
106+
};
107+
81108
const RunnerName: React.FC<RunnerNameProps> = (props) => {
82109
const { prefix } = props;
83110
const repName = `${prefix ?? "default"}:currentRun`;

0 commit comments

Comments
 (0)