Road to No Explicit Any Part 5: load3d Module (#8064)

## Summary
- Removes all `any` types from the load3d module
- Uses generics for EventCallback to provide type-safe event handling
- Types node parameters with LGraphNode
- Types onExecuted callback with NodeExecutionOutput
- Types Camera Config property casts with CameraConfig interface

## Changes
- `interfaces.ts`: EventCallback<T> generic, EventManagerInterface
generic methods
- `EventManager.ts`: Generic
emitEvent/addEventListener/removeEventListener
- `AnimationManager.ts`: setupModelAnimations originalModel typed as
GLTF union
- `Load3d.ts`: Event listener methods use EventCallback<T>
- `load3d.ts`: Node params typed as LGraphNode, onExecuted uses
NodeExecutionOutput, CameraConfig casts

## Test plan
- [x] `pnpm typecheck` passes
- [x] `pnpm lint` passes
- [x] `pnpm test:unit` passes

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8064-Road-to-No-Explicit-Any-Part-5-load3d-Module-2e96d73d365081efbc01f2d8a4f3c11f)
by [Unito](https://www.unito.io)
This commit is contained in:
Johnpaul Chiwetelu
2026-01-15 02:21:38 +01:00
committed by GitHub
parent 3069c24f81
commit 538f007f1d
6 changed files with 59 additions and 35 deletions

View File

@@ -1,9 +1,10 @@
import * as THREE from 'three'
import type { GLTF } from 'three/examples/jsm/loaders/GLTFLoader'
import {
type AnimationItem,
type AnimationManagerInterface,
type EventManagerInterface
import type {
AnimationItem,
AnimationManagerInterface,
EventManagerInterface
} from '@/extensions/core/load3d/interfaces'
export class AnimationManager implements AnimationManagerInterface {
@@ -38,7 +39,10 @@ export class AnimationManager implements AnimationManagerInterface {
this.eventManager.emitEvent('animationListChange', [])
}
setupModelAnimations(model: THREE.Object3D, originalModel: any): void {
setupModelAnimations(
model: THREE.Object3D,
originalModel: THREE.Object3D | THREE.BufferGeometry | GLTF | null
): void {
if (this.currentAnimation) {
this.currentAnimation.stopAllAction()
this.animationActions = []

View File

@@ -1,16 +1,16 @@
import { type EventCallback, type EventManagerInterface } from './interfaces'
export class EventManager implements EventManagerInterface {
private listeners: { [key: string]: EventCallback[] } = {}
private listeners: Record<string, EventCallback[]> = {}
addEventListener(event: string, callback: EventCallback): void {
addEventListener<T>(event: string, callback: EventCallback<T>): void {
if (!this.listeners[event]) {
this.listeners[event] = []
}
this.listeners[event].push(callback)
this.listeners[event].push(callback as EventCallback)
}
removeEventListener(event: string, callback: EventCallback): void {
removeEventListener<T>(event: string, callback: EventCallback<T>): void {
if (this.listeners[event]) {
this.listeners[event] = this.listeners[event].filter(
(cb) => cb !== callback
@@ -18,7 +18,7 @@ export class EventManager implements EventManagerInterface {
}
}
emitEvent(event: string, data?: any): void {
emitEvent<T>(event: string, data: T): void {
if (this.listeners[event]) {
this.listeners[event].forEach((callback) => callback(data))
}

View File

@@ -14,6 +14,7 @@ import { ViewHelperManager } from './ViewHelperManager'
import {
type CameraState,
type CaptureResult,
type EventCallback,
type Load3DOptions,
type MaterialMode,
type UpDirection
@@ -610,11 +611,11 @@ class Load3d {
this.forceRender()
}
addEventListener(event: string, callback: (data?: any) => void): void {
addEventListener<T>(event: string, callback: EventCallback<T>): void {
this.eventManager.addEventListener(event, callback)
}
removeEventListener(event: string, callback: (data?: any) => void): void {
removeEventListener<T>(event: string, callback: EventCallback<T>): void {
this.eventManager.removeEventListener(event, callback)
}

View File

@@ -47,8 +47,8 @@ export interface LightConfig {
intensity: number
}
export interface EventCallback {
(data?: any): void
export interface EventCallback<T = unknown> {
(data: T): void
}
export interface Load3DOptions {
@@ -128,9 +128,9 @@ export interface ViewHelperManagerInterface extends BaseManager {
}
export interface EventManagerInterface {
addEventListener(event: string, callback: EventCallback): void
removeEventListener(event: string, callback: EventCallback): void
emitEvent(event: string, data?: any): void
addEventListener<T>(event: string, callback: EventCallback<T>): void
removeEventListener<T>(event: string, callback: EventCallback<T>): void
emitEvent<T>(event: string, data: T): void
}
export interface AnimationManagerInterface extends BaseManager {
@@ -141,7 +141,10 @@ export interface AnimationManagerInterface extends BaseManager {
isAnimationPlaying: boolean
animationSpeed: number
setupModelAnimations(model: THREE.Object3D, originalModel: any): void
setupModelAnimations(
model: THREE.Object3D,
originalModel: THREE.Object3D | THREE.BufferGeometry | GLTF | null
): void
updateAnimationList(): void
setAnimationSpeed(speed: number): void
updateSelectedAnimation(index: number): void