Reputation: 117
Why do I have to hack the type definition from material: Material | Material[];
to material: Material;
to fix the error detailed below? TypeScript is seemingly assuming that the material
parameter is of type Material[]
even when I explicitly set it to Material. Am I missing something?
Typescript/ThreeJS Error:
this.obj3D.traverse((child) => {
if (child instanceof THREE.Mesh) {
// Error in line below:
// Property 'shading' does not exist on type 'Material | Material
child.material.shading = THREE.SmoothShading;
child.material.side = THREE.DoubleSide;
child.scale.set(this.scale, this.scale, this.scale);
child.castShadow = this.castShadow;
child.receiveShadow = true;
child.material.needsUpdate = true;
}
});
ThreeJS Type Definition:
export class Mesh extends Object3D {
constructor(geometry?: Geometry, material?: Material | Material[]);
constructor(geometry?: BufferGeometry, material?: Material | Material[]);
geometry: Geometry | BufferGeometry;
material: Material | Material[]; // Had to delete *| Material[]* to fix
drawMode: TrianglesDrawModes;
setDrawMode(drawMode: TrianglesDrawModes): void;
updateMorphTargets(): void;
getMorphTargetIndexByName(name: string): number;
raycast(raycaster: Raycaster, intersects: any): void;
}
Upvotes: 1
Views: 338
Reputation: 330216
As far as I can tell from your screenshots, the material
property of a Mesh
object could either be a Material
object or an array of Material
objects. TypeScript is helpfully warning you that you are treating child.material
as a single Material
object without checking if it actually is one.
Unless you are absolutely sure that every instance of Mesh
your code will ever touch has a single Material
object and not an array as its material
property, it's a bad idea for you to alter the type definition in the library. If the library declaration file is correct and some Mesh
objects have arrays of Material
objects, your code will behave incorrectly at runtime as soon as you try to set the shading
property of an array.
Instead, the right thing to do would be to check whether child.material
is an array, like:
const doStuffToMaterial = function(m: Material):void {
m.shading = THREE.SmoothShading;
m.side = THREE.DoubleSide;
}
// check for an array
if (Array.isArray(child.material)) {
child.material.forEach(doStuffToMaterial);
} else {
doStuffToMaterial(child.material);
}
which handles the array case by performing the same action on each element.
Or, if you're sure that child.material
is not an array, you can do something like:
// Assert that it's not an array
const m = child.material as Material;
m.shading = THREE.SmoothShading;
m.side = THREE.DoubleSide;
where you tell TypeScript you know that child.material
is not an array, by using a type assertion. This could still do bad things at runtime if your assertion turns out to be wrong, but presumably you know better.
I hope one of those solutions works for you. Good luck!
Upvotes: 1