Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Strongly typed events (WIP) #572

Closed
wants to merge 23 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion types/three/examples/jsm/controls/ArcballControls.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,13 @@ export enum ArcballControlsMouseActionKeys {
CTRL = 'CTRL',
}

export class ArcballControls extends EventDispatcher {
export interface ArcballControlsEventMap {
change: {};
start: {};
end: {};
}

export class ArcballControls extends EventDispatcher<ArcballControlsEventMap> {
camera: Camera | null;
domElement: HTMLElement;
scene?: Scene | null | undefined;
Expand Down
10 changes: 9 additions & 1 deletion types/three/examples/jsm/controls/DragControls.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
import { Camera, EventDispatcher, Object3D, Raycaster } from '../../../src/Three.js';

export class DragControls extends EventDispatcher {
export interface DragControlsEventMap {
hoveron: { object: Object3D };
hoveroff: { object: Object3D };
dragstart: { object: Object3D };
drag: { object: Object3D };
dragend: { object: Object3D };
}

export class DragControls extends EventDispatcher<DragControlsEventMap> {
constructor(objects: Object3D[], camera: Camera, domElement?: HTMLElement);

object: Camera;
Expand Down
6 changes: 5 additions & 1 deletion types/three/examples/jsm/controls/FlyControls.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { Camera, EventDispatcher } from '../../../src/Three.js';

export class FlyControls extends EventDispatcher {
export interface FlyControlsEventMap {
change: {};
}

export class FlyControls extends EventDispatcher<FlyControlsEventMap> {
constructor(object: Camera, domElement?: HTMLElement);

autoForward: boolean;
Expand Down
19 changes: 8 additions & 11 deletions types/three/examples/jsm/controls/OrbitControls.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import { Camera, MOUSE, TOUCH, Vector3 } from '../../../src/Three.js';
import { Camera, EventDispatcher, MOUSE, TOUCH, Vector3 } from '../../../src/Three.js';

export interface OrbitControlsEventMap {
change: {};
start: {};
end: {};
}

/**
* Orbit controls allow the camera to orbit around a target.
Expand All @@ -7,7 +13,7 @@ import { Camera, MOUSE, TOUCH, Vector3 } from '../../../src/Three.js';
* @param domElement - The HTML element used for
* event listeners.
*/
export class OrbitControls {
export class OrbitControls extends EventDispatcher<OrbitControlsEventMap> {
constructor(object: Camera, domElement?: HTMLElement);

/**
Expand Down Expand Up @@ -272,13 +278,4 @@ export class OrbitControls {
* Returns the distance from the camera to the target.
*/
getDistance(): number;

// EventDispatcher mixins
addEventListener(type: string, listener: (event: any) => void): void;

hasEventListener(type: string, listener: (event: any) => void): boolean;

removeEventListener(type: string, listener: (event: any) => void): void;

dispatchEvent(event: { type: string; target: any }): void;
}
8 changes: 7 additions & 1 deletion types/three/examples/jsm/controls/TrackballControls.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { Camera, EventDispatcher, MOUSE, Vector3 } from '../../../src/Three.js';

export class TrackballControls extends EventDispatcher {
export interface TrackballControlsEventMap {
change: {};
start: {};
end: {};
}

export class TrackballControls extends EventDispatcher<TrackballControlsEventMap> {
constructor(object: Camera, domElement?: HTMLElement);

object: Camera;
Expand Down
37 changes: 35 additions & 2 deletions types/three/examples/jsm/controls/TransformControls.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,38 @@
import { Object3D, Camera, MOUSE, Raycaster, Mesh, Vector3, Quaternion } from '../../../src/Three.js';
import { Object3D, Camera, MOUSE, Raycaster, Mesh, Vector3, Quaternion, Object3DEventMap } from '../../../src/Three.js';

export class TransformControls extends Object3D {
export interface TransformControlsEventMap extends Object3DEventMap {
change: {};
mouseDown: {};
mouseUp: {};
objectChange: {};
'camera-changed': { value: unknown };
'object-changed': { value: unknown };
'enabled-changed': { value: unknown };
'axis-changed': { value: unknown };
'mode-changed': { value: unknown };
'translationSnap-changed': { value: unknown };
'rotationSnap-changed': { value: unknown };
'scaleSnap-changed': { value: unknown };
'space-changed': { value: unknown };
'size-changed': { value: unknown };
'dragging-changed': { value: unknown };
'showX-changed': { value: unknown };
'showY-changed': { value: unknown };
'showZ-changed': { value: unknown };
'worldPosition-changed': { value: unknown };
'worldPositionStart-changed': { value: unknown };
'worldQuaternion-changed': { value: unknown };
'worldQuaternionStart-changed': { value: unknown };
'cameraPosition-changed': { value: unknown };
'cameraQuaternion-changed': { value: unknown };
'pointStart-changed': { value: unknown };
'pointEnd-changed': { value: unknown };
'rotationAxis-changed': { value: unknown };
'rotationAngle-changed': { value: unknown };
'eye-changed': { value: unknown };
}

export class TransformControls extends Object3D<TransformControlsEventMap> {
constructor(object: Camera, domElement?: HTMLElement);

domElement: HTMLElement;
Expand All @@ -20,6 +52,7 @@ export class TransformControls extends Object3D {
showX: boolean;
showY: boolean;
showZ: boolean;

readonly isTransformControls: true;
mouseButtons: { LEFT: MOUSE; MIDDLE: MOUSE; RIGHT: MOUSE };

Expand Down
15 changes: 14 additions & 1 deletion types/three/examples/jsm/interactive/InteractiveGroup.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,17 @@
import { WebGLRenderer, Camera, Group } from 'three';
import { Camera, Group, Object3D, Object3DEventMap, Vector2, WebGLRenderer } from '../../../src/Three.js';

export interface InteractiveObject3DEventMap extends Object3DEventMap {
hoveron: { data: Vector2 };
pointerdown: { data: Vector2 };
pointerup: { data: Vector2 };
pointermove: { data: Vector2 };
mousedown: { data: Vector2 };
mouseup: { data: Vector2 };
mousemove: { data: Vector2 };
click: { data: Vector2 };
}

export class InteractiveObject3D extends Object3D<InteractiveObject3DEventMap> {}

export class InteractiveGroup extends Group {
constructor(renderer: WebGLRenderer, camera: Camera);
Expand Down
9 changes: 7 additions & 2 deletions types/three/examples/jsm/webxr/XREstimatedLight.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { DirectionalLight, Group, LightProbe, Texture, WebGLRenderer } from '../../../src/Three.js';
import { DirectionalLight, Group, LightProbe, Texture, WebGLRenderer, Object3DEventMap } from '../../../src/Three.js';

export class SessionLightProbe {
xrLight: XREstimatedLight;
Expand All @@ -23,7 +23,12 @@ export class SessionLightProbe {
dispose: () => void;
}

export class XREstimatedLight extends Group {
export interface XREstimatedLightEventMap extends Object3DEventMap {
estimationstart: {};
estimationend: {};
}

export class XREstimatedLight extends Group<XREstimatedLightEventMap> {
lightProbe: LightProbe;
directionalLight: DirectionalLight;
environment: Texture;
Expand Down
7 changes: 6 additions & 1 deletion types/three/src/animation/AnimationMixer.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@ import { EventDispatcher } from './../core/EventDispatcher.js';
import { Object3D } from '../core/Object3D.js';
import { AnimationObjectGroup } from './AnimationObjectGroup.js';

export class AnimationMixer extends EventDispatcher {
export interface AnimationMixerEventMap {
loop: { action: AnimationAction; loopDelta: number };
finished: { action: AnimationAction; direction: number };
}

export class AnimationMixer extends EventDispatcher<AnimationMixerEventMap> {
constructor(root: Object3D | AnimationObjectGroup);

/**
Expand Down
2 changes: 1 addition & 1 deletion types/three/src/core/BufferGeometry.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ export type NormalOrGLBufferAttributes = Record<
*/
export class BufferGeometry<
Attributes extends NormalOrGLBufferAttributes = NormalBufferAttributes,
> extends EventDispatcher {
> extends EventDispatcher<{ dispose: {} }> {
/**
* This creates a new {@link THREE.BufferGeometry | BufferGeometry} object.
*/
Expand Down
42 changes: 30 additions & 12 deletions types/three/src/core/EventDispatcher.d.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
export interface BaseEvent {
type: string;
/**
* The minimal basic Event that can be dispatched by a {@link EventDispatcher<>}.
*/
export interface BaseEvent<TEventType extends string = string> {
readonly type: TEventType;
}

/**
* Event object.
* The minimal expected contract of a fired Event that was dispatched by a {@link EventDispatcher<>}.
*/
export interface Event extends BaseEvent {
target?: any;
[attachment: string]: any;
export interface Event<TEventType extends string = string, TTarget = unknown> {
readonly type: TEventType;
readonly target: TTarget;
}
export type EventListener<E, T, U> = (event: E & { type: T } & { target: U }) => void;

export type EventListener<TEventData, TEventType extends string, TTarget> = (
event: TEventData & Event<TEventType, TTarget>,
) => void;

/**
* JavaScript events for custom objects
Expand All @@ -32,7 +38,7 @@ export type EventListener<E, T, U> = (event: E & { type: T } & { target: U }) =>
* @see {@link https://threejs.org/docs/index.html#api/en/core/EventDispatcher | Official Documentation}
* @see {@link https://github.com/mrdoob/three.js/blob/master/src/core/EventDispatcher.js | Source}
*/
export class EventDispatcher<E extends BaseEvent = Event> {
export class EventDispatcher<TEventMap extends {} = {}> {
/**
* Creates {@link THREE.EventDispatcher | EventDispatcher} object.
*/
Expand All @@ -43,25 +49,37 @@ export class EventDispatcher<E extends BaseEvent = Event> {
* @param type The type of event to listen to.
* @param listener The function that gets called when the event is fired.
*/
addEventListener<T extends E['type']>(type: T, listener: EventListener<E, T, this>): void;
addEventListener<T extends Extract<keyof TEventMap, string>>(
type: T,
listener: EventListener<TEventMap[T], T, this>,
): void;
addEventListener<T extends string>(type: T, listener: EventListener<{}, T, this>): void;

/**
* Checks if listener is added to an event type.
* @param type The type of event to listen to.
* @param listener The function that gets called when the event is fired.
*/
hasEventListener<T extends E['type']>(type: T, listener: EventListener<E, T, this>): boolean;
hasEventListener<T extends Extract<keyof TEventMap, string>>(
type: T,
listener: EventListener<TEventMap[T], T, this>,
): boolean;
hasEventListener<T extends string>(type: T, listener: EventListener<{}, T, this>): boolean;

/**
* Removes a listener from an event type.
* @param type The type of the listener that gets removed.
* @param listener The listener function that gets removed.
*/
removeEventListener<T extends E['type']>(type: T, listener: EventListener<E, T, this>): void;
removeEventListener<T extends Extract<keyof TEventMap, string>>(
type: T,
listener: EventListener<TEventMap[T], T, this>,
): void;
removeEventListener<T extends string>(type: T, listener: EventListener<{}, T, this>): void;

/**
* Fire an event type.
* @param event The event that gets fired.
*/
dispatchEvent(event: E): void;
dispatchEvent<T extends Extract<keyof TEventMap, string>>(event: BaseEvent<T> & TEventMap[T]): void;
}
29 changes: 17 additions & 12 deletions types/three/src/core/Object3D.d.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,32 @@
import { Vector3 } from './../math/Vector3.js';
import { Euler } from './../math/Euler.js';
import { Quaternion } from './../math/Quaternion.js';
import { Matrix4 } from './../math/Matrix4.js';
import { Matrix3 } from './../math/Matrix3.js';
import { Vector3 } from '../math/Vector3.js';
import { Euler } from '../math/Euler.js';
import { Quaternion } from '../math/Quaternion.js';
import { Matrix4 } from '../math/Matrix4.js';
import { Matrix3 } from '../math/Matrix3.js';
import { Layers } from './Layers.js';
import { WebGLRenderer } from './../renderers/WebGLRenderer.js';
import { Scene } from './../scenes/Scene.js';
import { Camera } from './../cameras/Camera.js';
import { Material } from './../materials/Material.js';
import { Group } from './../objects/Group.js';
import { WebGLRenderer } from '../renderers/WebGLRenderer.js';
import { Scene } from '../scenes/Scene.js';
import { Camera } from '../cameras/Camera.js';
import { Material } from '../materials/Material.js';
import { Group } from '../objects/Group.js';
import { Intersection, Raycaster } from './Raycaster.js';
import { EventDispatcher, BaseEvent, Event } from './EventDispatcher.js';
import { EventDispatcher } from './EventDispatcher.js';
import { BufferGeometry } from './BufferGeometry.js';
import { AnimationClip } from '../animation/AnimationClip.js';

export interface Object3DEventMap {
added: {};
removed: {};
}

/**
* This is the base class for most objects in three.js and provides a set of properties and methods for manipulating objects in 3D space.
* @remarks Note that this can be used for grouping objects via the {@link THREE.Object3D.add | .add()} method which adds the object as a child,
* however it is better to use {@link THREE.Group | Group} for this.
* @see {@link https://threejs.org/docs/index.html#api/en/core/Object3D | Official Documentation}
* @see {@link https://github.com/mrdoob/three.js/blob/master/src/core/Object3D.js | Source}
*/
export class Object3D<E extends BaseEvent = Event> extends EventDispatcher<E> {
export class Object3D<TEventMap extends Object3DEventMap = Object3DEventMap> extends EventDispatcher<TEventMap> {
/**
* This creates a new {@link Object3D} object.
*/
Expand Down
2 changes: 1 addition & 1 deletion types/three/src/core/RenderTarget.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export interface RenderTargetOptions {
encoding?: TextureEncoding | undefined;
}

export class RenderTarget<TTexture extends Texture | Texture[] = Texture> extends EventDispatcher {
export class RenderTarget<TTexture extends Texture | Texture[] = Texture> extends EventDispatcher<{ dispose: {} }> {
constructor(width?: number, height?: number, options?: RenderTargetOptions);

readonly isRenderTarget: true;
Expand Down
2 changes: 1 addition & 1 deletion types/three/src/core/UniformsGroup.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { Usage } from '../constants.js';
* @see Example: {@link https://threejs.org/examples/#webgl2_ubo | WebGL2 / UBO}
* @see {@link https://github.com/mrdoob/three.js/blob/master/src/core/UniformsGroup.js | Source}
*/
export class UniformsGroup extends EventDispatcher {
export class UniformsGroup extends EventDispatcher<{ dispose: {} }> {
constructor();

readonly isUniformsGroup: true;
Expand Down
2 changes: 1 addition & 1 deletion types/three/src/materials/Material.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export interface MaterialParameters {
/**
* Materials describe the appearance of objects. They are defined in a (mostly) renderer-independent way, so you don't have to rewrite materials if you decide to use a different renderer.
*/
export class Material extends EventDispatcher {
export class Material extends EventDispatcher<{ dispose: {} }> {
constructor();

alphaHash: boolean;
Expand Down
4 changes: 2 additions & 2 deletions types/three/src/objects/Group.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Object3D } from './../core/Object3D.js';
import { Object3D, Object3DEventMap } from '../core/Object3D.js';

/**
* Its purpose is to make working with groups of objects syntactically clearer.
Expand All @@ -22,7 +22,7 @@ import { Object3D } from './../core/Object3D.js';
* @see {@link https://threejs.org/docs/index.html#api/en/objects/Group | Official Documentation}
* @see {@link https://github.com/mrdoob/three.js/blob/master/src/objects/Group.js | Source}
*/
export class Group extends Object3D {
export class Group<TEventMap extends Object3DEventMap = Object3DEventMap> extends Object3D<TEventMap> {
/**
* Creates a new {@link Group}.
*/
Expand Down
Loading