InstancedMesh returned from pickInfo is AbstractMesh

Apologies if this is not the correct forum for this question. I suspect it’s a TypeScript issue that I just don’t understand yet.

I have loaded a .gltf and it contains numerous Mesh and InstancedMesh objects. I correctly configured POINTERDOWN event that returns info for clicked elements of the scene.

However, I get some strange results when clicking on an InstancedMesh. When I click on one and log it, it is clearly an InstancedMesh, and pickInfo.pickedMesh.isAnInstance returns true. But when I try to call sourceMesh() on it, I get the following TS error:

TS2339: Property ‘sourceMesh’ does not exist on type ‘AbstractMesh’.

My Googling so far has not yielded much, but there was a thread here about version mismatching.

Here is my package.json:
{
“name”: “webpack-demo”,
“version”: “1.0.0”,
“description”: “”,
“private”: true,
“scripts”: {
“build”: “webpack”,
“start”: “webpack serve”,
“watch”: “webpack --watch”
},
“keywords”: ,
“author”: “”,i
“license”: “ISC”,
“devDependencies”: {
@babylonjs/core”: “^4.2.0”,
@babylonjs/loaders”: “^4.2.0”,
@types/node”: “^16.11.6”,
@types/pubsub-js”: “^1.8.3”,
@types/react-dom”: “^16.0.9”,
“clean-webpack-plugin”: “^4.0.0”,
“css-loader”: “^6.3.0”,
“html-webpack-plugin”: “^5.3.2”,
“pubsub-js”: “^1.9.3”,
“style-loader”: “^3.3.0”,
“webpack”: “^5.54.0”,
“webpack-cli”: “^4.8.0”,
“webpack-dev-server”: “^4.3.0”
},
“dependencies”: {
“lodash”: “^4.17.21”,
“ts-loader”: “^9.2.6”,
“typescript”: “^4.4.3”
}
}

And my TS config:
{
“compilerOptions”: {
“types”: ["@babylonjs/core"],
“target”: “es6”,
“module”: “commonjs”,
“noResolve”: false,
“noImplicitAny”: false,
“sourceMap”: true,
“preserveConstEnums”: true,
“lib”: [“dom”, “es6”],
“rootDir”: “src”
}
}

If anyone can offer some advice or point me towards the resources I need to consult, I would be very grateful. Thanks in advance.

1 Like

Welcome aboard!

What you see is the normal behaviour because the type of pickedMesh is AbstractMesh because it can either be a InstancedMesh or a Mesh (maybe even other types), both classes inheriting from AbstractMesh. So, trying to access sourceMesh without safeguard is an error because the mesh could not be an instanced mesh.

You should do something like:

if (pickedMesh.getClassName() === "InstancedMesh") {
    const sourceMesh = (pickedMesh as InstancedMesh).sourceMesh;
}

or:

function isInstancedMesh(mesh: AbstractMesh): mesh is InstancedMesh {
    return mesh.getClassName() === "InstancedMesh";
}

if (isInstancedMesh(pickedMesh)) {
    const sourceMesh = pickedMesh.sourceMesh;
}

Warning: code not tested!

5 Likes

This was the missing piece to my puzzle. Thank you so much!

1 Like

Note that you might find that using instanceof will be a bit more straight forward in TypeScript since it will automatically narrow the type, but doing this is very slow compared to @Evgeni_Popov’s solution.

// don't do this as it is very slow
if (pickedMesh instanceof InstancedMesh) {
    const sourceMesh = pickedMesh.sourceMesh;
}
1 Like