Havok `EventType` TypeScript issue

In the function

HP_Body_SetEventMask(bodyId : HP_BodyId, eventMask : number): Result;

eventMask is a number. An acceptable value for eventMask is EventType.COLLISION_STARTED.value. However, we cannot use .value in TypeScript unless we use // @ts-ignore

Is there a way we can use HP_Body_SetEventMask() in TypeScript without // @ts-ignore? Thanks!

GitHub Source demonstrating the TypeScript issue

1 Like

You don’t have to use .value. You can pass directly the enum member.

EventType is a number enum:

declare enum EventType {
    COLLISION_STARTED,
    COLLISION_CONTINUED,
    COLLISION_FINISHED,
    TRIGGER_ENTERED,
    TRIGGER_EXITED
}

Unfortunately, we do have to use .value

The .d.ts types file suggests that EventType.__ is an enum/number. However, on the JS side after loading Havok, EventType.__ is actually an object of type { value: number }

Here’s the line in the Babylon.js source code that uses .value for EventType:

const collideEvents = this._hknp.EventType.COLLISION_STARTED.value | this._hknp.EventType.COLLISION_CONTINUED.value | this._hknp.EventType.COLLISION_FINISHED.value;

You can also open the Dev Console in the Playground and run the following code to see this:

But your project is in Typescript. You can use enums as is.

No errors.

It’s true that you will get no TypeScript errors by omitting .value. However, collision callbacks will not fire if .value is omitted. This is why the Babylon.js source code uses .value

Try defining your own enum:

enum HKEventType {
    COLLISION_STARTED = 0,
    COLLISION_CONTINUED = 1,
    COLLISION_FINISHED = 2,
    TRIGGER_ENTERED = 3,
    TRIGGER_EXITED = 4
}

and use this enum

OR:

const COLLISION_STARTED = HK.EventType["COLLISION_STARTED" as keyof typeof HK.EventType]

OR:

(<{value: number}><unknown>HK.EventType.COLLISION_CONTINUED).value - you can create your own type too

OR:

cast to any and surpress warnings

@roland Thank you for taking the time to look into this and sharing these workarounds :slight_smile:

Respectfully, if we must use a workaround, I’m fine with just using // @ts-ignore with .value as the Babylon.js source code does.

I hope that the Babylon.js team could consider a change so that we don’t need to use a workaround. @RaananW @Cedric I’m curious to hear your thoughts on this when you have time. It seems like there are 2 approaches for a solution:

  1. On the JS side: Make EventType.COLLISION_STARTED a number instead of an object of type { value: number }
  2. On the TS .d.ts side: Expose .value on EventType somehow
3 Likes

The workaround seems to work:

import type { HavokPhysicsWithBindings } from '@babylonjs/havok';

declare global {
	const HK: HavokPhysicsWithBindings & {
		EventType: {
			COLLISION_STARTED: { value: number };
			COLLISION_CONTINUED: { value: number };
			COLLISION_FINISHED: { value: number };
		};
	};
}

const flags = HK.EventType.COLLISION_STARTED.value | HK.EventType.COLLISION_CONTINUED.value;

Maybe @eoin will have some thoughts.

1 Like