Skip to content

Commit b744a75

Browse files
committed
Add generic prop type support
1 parent 6b53fc9 commit b744a75

File tree

1 file changed

+45
-27
lines changed

1 file changed

+45
-27
lines changed

src/index.tsx

Lines changed: 45 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,76 @@
11
import diff from "microdiff";
22
import p5 from "p5";
3-
import React, { createRef, FC, memo, useState } from "react";
3+
import React, { createRef, memo, useState } from "react";
44
import { useIsomorphicEffect } from "rooks";
55

66
type Wrapper = HTMLDivElement;
7+
type WithChildren<T = unknown> = T & { children?: React.ReactNode };
8+
type InputProps<Props extends SketchProps = SketchProps> = Props & {
9+
sketch: Sketch<Props>;
10+
};
11+
export type Sketch<Props extends SketchProps = SketchProps> = (
12+
instance: P5Instance<Props>
13+
) => void;
14+
export type SketchProps = { [key: string]: unknown };
15+
export type P5WrapperProps<Props extends SketchProps = SketchProps> =
16+
WithChildren<InputProps<Props>>;
17+
export type P5Instance<Props extends SketchProps = SketchProps> = p5 & {
18+
updateWithProps?: (props: Props) => void;
19+
};
720

8-
export interface SketchProps {
9-
[key: string]: any;
10-
}
11-
12-
export interface Sketch {
13-
(instance: P5Instance): void;
14-
}
15-
16-
export interface P5WrapperProps extends SketchProps {
17-
sketch: Sketch;
18-
}
19-
20-
export interface P5Instance extends p5 {
21-
updateWithProps?: (props: SketchProps) => void;
22-
}
23-
24-
function createCanvas(sketch: Sketch, wrapper: Wrapper): P5Instance {
21+
function createCanvas<Props extends SketchProps = SketchProps>(
22+
sketch: Sketch<Props>,
23+
wrapper: Wrapper
24+
): P5Instance<Props> {
2525
return new p5(sketch, wrapper);
2626
}
2727

28-
const ReactP5WrapperComponent: FC<P5WrapperProps> = ({
28+
function ReactP5WrapperComponent<Props extends SketchProps = SketchProps>({
2929
sketch,
3030
children,
3131
...props
32-
}) => {
32+
}: P5WrapperProps<Props>) {
3333
const wrapperRef = createRef<Wrapper>();
34-
const [instance, setInstance] = useState<P5Instance>();
34+
const [instance, setInstance] = useState<P5Instance<Props>>();
3535

3636
useIsomorphicEffect(() => {
3737
if (wrapperRef.current === null) {
3838
return;
3939
}
4040

4141
instance?.remove();
42-
const canvas = createCanvas(sketch, wrapperRef.current);
42+
const canvas = createCanvas<Props>(sketch, wrapperRef.current);
4343
setInstance(canvas);
4444
}, [sketch]);
4545

46-
useIsomorphicEffect(() => {
47-
instance?.updateWithProps?.(props);
48-
}, [props, instance]);
46+
useIsomorphicEffect(
47+
/**
48+
* The `as any` cast is begrudgingly required due to a known limitation of the TypeScript compiler as demonstrated in issues:
49+
*
50+
* - https://github.com/microsoft/TypeScript/issues/35858
51+
* - https://github.com/microsoft/TypeScript/issues/37670
52+
*
53+
* Potentially this will be resolved by this PR once it is eventually merged:
54+
*
55+
* - https://github.com/microsoft/TypeScript/pull/42382
56+
*
57+
* Etiher way, until a resolution is merged into the TypeScript compiler that addressed this isssue, we need to use this workaround.
58+
* We could also remove this if we manage find a reasonable workaround of some sort ourselves of course.
59+
* If a workaround / change of implementation comes to mind, please raise an issue on the repository or feel free to open a PR!
60+
*/
61+
() => instance?.updateWithProps?.(props as any),
62+
[props, instance]
63+
);
4964

5065
useIsomorphicEffect(() => () => instance?.remove(), []);
5166

5267
return <div ref={wrapperRef}>{children}</div>;
53-
};
68+
}
5469

55-
function propsAreEqual(previous: P5WrapperProps, next: P5WrapperProps) {
70+
function propsAreEqual<Props extends SketchProps = SketchProps>(
71+
previous: P5WrapperProps<Props>,
72+
next: P5WrapperProps<Props>
73+
) {
5674
const differences = diff(previous, next);
5775

5876
return differences.length === 0;

0 commit comments

Comments
 (0)