Skip to content

Commit 4f66cf6

Browse files
author
Philipp Molitor
authored
Merge pull request #10 from PhilippMolitor/feature/module-augmentation
Feature/module augmentation
2 parents d9dd344 + 9812312 commit 4f66cf6

File tree

4 files changed

+113
-9
lines changed

4 files changed

+113
-9
lines changed

README.md

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,3 +181,57 @@ export async function fetchLoaderConfig(
181181
```
182182

183183
You can then use it to construct a `UnityContext` and pass this context to your `UnityRenderer` via the `context` prop.
184+
185+
## Module augmentation
186+
187+
Take the following example:
188+
189+
```typescript
190+
// create some context
191+
const ctx = new UnityContext({ ... });
192+
193+
// handles some "info" event with one parameter of type string
194+
ctx.on('info', (message: string) => {
195+
console.log(message);
196+
});
197+
```
198+
199+
The parameter `message` has to be explicitly defined as `string` each time a handler of for the event name `info` would be registered.
200+
In order to make use of TypeScript to its fullest extent, you can augment an Interface of the library to get autocompletion and type-safety features here.
201+
202+
Put this either in a file importing `react-unity-renderer` or create a new `unity.d.ts` somewhere in your `src` or (if you have that) `typings` directory:
203+
204+
```typescript
205+
// must be imported, else the module will be redefined,
206+
// and this causes all sorts of errors.
207+
import 'react-unity-renderer';
208+
209+
// module augmentation
210+
declare module 'react-unity-renderer' {
211+
// this is the interface providing autocompletion
212+
interface EventSignatures {
213+
// "info" is the event name
214+
// the type on the right side is anything that would match TypeScript's
215+
// Parameters<> helper type
216+
info: [message: string];
217+
218+
// also possible:
219+
info: [string];
220+
'some-event': [number, debug: string];
221+
// note that all parametrs names are just labels, so they are fully optional.
222+
}
223+
}
224+
```
225+
226+
Now, any defined event will be auto-completed with its types for `UnityContext.on(...)`:
227+
228+
```typescript
229+
// create some context
230+
const ctx = new UnityContext({ ... });
231+
232+
// "info" will be suggested by your IDE
233+
// "message" is now of type string
234+
ctx.on('info', (message) => {
235+
console.log(message);
236+
});
237+
```

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@ export {
33
UnityContext,
44
UnityLoaderConfig,
55
UnityInstanceConfig,
6+
EventSignatures,
67
} from './lib/context';
78
export { UnityRenderer, UnityRendererProps } from './components/UnityRenderer';

src/lib/context.ts

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
export interface UnityInstanceConfig {
2-
frameworkUrl: string;
32
codeUrl: string;
3+
frameworkUrl: string;
44
dataUrl: string;
55
memoryUrl?: string;
66
symbolsUrl?: string;
@@ -15,7 +15,22 @@ export interface UnityLoaderConfig extends UnityInstanceConfig {
1515
loaderUrl: string;
1616
}
1717

18-
type UnityEventCallback = (...params: any) => void;
18+
/**
19+
* An interface containing event names and their handler parameter signatures.
20+
* This interface is supposed to be augmented via module augmentation by the
21+
* user.
22+
*/
23+
export interface EventSignatures {}
24+
25+
/**
26+
* Refers to a callback function with any parameters.
27+
*/
28+
type EventCallback = (...params: any) => void;
29+
30+
/**
31+
* Defines a weak union type, which can fallback to another type.
32+
*/
33+
type WeakUnion<T, F> = T | (F & {});
1934

2035
/**
2136
* Defines a Unity WebGL context.
@@ -29,7 +44,7 @@ export class UnityContext {
2944

3045
private instance?: UnityInstance;
3146

32-
private eventCallbacks: { [name: string]: UnityEventCallback } = {};
47+
private eventCallbacks: { [name: string]: EventCallback } = {};
3348

3449
/**
3550
* Creates a new `UnityContext` and registers the global event callback.
@@ -92,7 +107,7 @@ export class UnityContext {
92107
}
93108

94109
/**
95-
* Emits a remote procedure call towards the running Unity instance.
110+
* Emits a message to the running Unity instance.
96111
*
97112
* @param {string} objectName The `GameObject` on which to call the method.
98113
* @param {string} methodName The name of the method which should be invoked.
@@ -118,7 +133,12 @@ export class UnityContext {
118133
* @param {UnityEventCallback} callback The callback which should be invoked
119134
* upon the occurence of this event.
120135
*/
121-
public on<T extends UnityEventCallback>(name: string, callback: T): void {
136+
public on<T extends WeakUnion<keyof EventSignatures, string>>(
137+
name: WeakUnion<keyof EventSignatures, T>,
138+
callback: (
139+
...params: T extends keyof EventSignatures ? EventSignatures[T] : any
140+
) => void
141+
): void {
122142
this.eventCallbacks[name] = callback;
123143
}
124144

@@ -141,7 +161,7 @@ export class UnityContext {
141161
* @returns {UnityEventCallback} The callback which should
142162
* handle the event.
143163
*/
144-
private bridgeCallback(name: string): UnityEventCallback {
164+
private bridgeCallback(name: string): EventCallback {
145165
if (this.eventCallbacks && this.eventCallbacks[name])
146166
return this.eventCallbacks[name];
147167

typings/unity.d.ts

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,40 @@ declare class UnityInstance {
1313
}
1414

1515
declare interface Window {
16-
UnityBridge: (name: string) => (...params: any) => void;
16+
/**
17+
* Global function returning a callback for the requested event.
18+
* Will `console.warn()` and return a dummy callback in case the specified event
19+
* name has no registered handler.
20+
*
21+
* @param {string} name name of the event
22+
*/
23+
UnityBridge(name: string): (...params: any) => void;
1724

25+
/**
26+
* Mapper to the native JavaScript function from Unity's loader script,
27+
* which loads and renders a WebGL build inside a `<canvas>` element.
28+
*
29+
* @param {HTMLCanvasElement} canvas The `<canvas>` object to which the game
30+
* should be rendered.
31+
* @param {UnityInstanceConfig} parameters The configuration containing all
32+
* required information to load a WebGL build.
33+
* @param {(progress: number) => void} [onProgress] Callback function
34+
* for Unity loading progress changes. Ranges from `0` to `1.0`.
35+
*/
1836
createUnityInstance(
19-
element: HTMLCanvasElement,
20-
parameters: UnityInstanceConfig,
37+
canvas: HTMLCanvasElement,
38+
config: {
39+
codeUrl: string;
40+
frameworkUrl: string;
41+
dataUrl: string;
42+
memoryUrl?: string;
43+
symbolsUrl?: string;
44+
streamingAssetsUrl?: string;
45+
companyName?: string;
46+
productName?: string;
47+
productVersion?: string;
48+
modules?: { [key: string]: any };
49+
},
2150
onProgress?: (progress: number) => void
2251
): Promise<UnityInstance>;
2352
}

0 commit comments

Comments
 (0)