Imagine a scenario like this:
type BodyTypeA = {
width: number;
height: number;
label: string;
id: string;
importantNumber: number;
// Various other BodyTypeA specific fields
}
type BodyTypeB = {
width: number;
height: number;
}
type BodyTypeC = {
width: number;
height: number;
}
class PhysicsObject {
body: BodyTypeA | BodyTypeB | BodyTypeC
createFromSprite(...) {
this.body = // Implementation for creating a BodyTypeA body
}
createFromJson() {
this.body = // This will assign a BodyTypeB body
}
createFromWhatever() {
this.body = // This will set the body to BodyTypeC body
}
}
I quickly jotted that down, so there might be some flaws.
The issue I'm facing involves instances of PhysicsObject
. The PhysicsObject
class and its typings are part of a third-party library, which I'm unable or unwilling to modify. Every PhysicsObject
has a body
field with three possible BodyTypes
, and although it seems unnecessary, that's how it was designed.
Primarily, I only generate bodies
for PhysicsObjects
using the createFromSprite
method, which produces a BodyTypeA
body for the PhysicsObject
.
The challenge arises when I try to assign values to properties such as id
, label
, and many others for the body. Each time, I have to assert that the physicsObject.body
is of type BodyTypeA
:
let physicsObject = new PhysicsObject();
physicsObject.createFromSprite(...);
(physicsObject.body as BodyTypeA).label = "abc";
(physicsObject.body as BodyTypeA).id = 124;
let saveImportantNumber = (physicsObject.body as BodyTypeA).importantNumber;
...
I'm exploring ways to persist the type assertion without modifying any existing code or types from the third-party library. Is there a way to achieve this more efficiently?
Here's an idea of what I'd like to do:
let physicsObject = new PhysicsObject();
physicsObject.createFromSprite(...);
// Assertion block?
(physicsObject.body as BodyTypeA) {
// Avoid repetitive type assertions
physicsObject.body.label = "abc";
physicsObject.body.id = 124;
let saveImportantNumber = physicsObject.body.importantNumber;
...
}
// Simply assert it and somehow retain the instance type
physicsObject.body as BodyTypeA;
// Skip the repeated type assertions
physicsObject.body.label = "abc";
physicsObject.body.id = 124;
let saveImportantNumber = physicsObject.body.importantNumber;
...
Is there another approach to achieving this that I may not be aware of?
When using createFromSprite
to create the body
, the type of the body
does not automatically narrow down to
BodyTypeA</code. It seems that TypeScript does not perform this "collapsing" operation in this case. It appears that <code>createFromSprite
does not explicitly produce a BodyTypeA
body; instead, it maintains a general structure. However, fields like id
and label
certainly do not exist on PhysicsObject.body
created through methods other than CreateFromSprite
.