When using typescript, a Three.Light object doesn't have the .isPointLight property defined. Even casting it to a Three.PointLight doesn't have that property. Perhaps it would be good if the base Three.Light object always had those three properties defined in typescript? Then you could type-safely test the light type in typescript:
if (light.isSpotLight) {
let spot = light as Three.SpotLight
// do spotlight stuff
}
Alternatively an extensible light.getType() could be written, but the current way should work once types are declared.
light.isSpotLight === true doesn't work in Typescript?
Correct -- unless I made an error of some kind, Three.Light has no property isSpotLight. You get a compiler error.
How about...
light.isSpotLight !== undefined && light.isSpotLight === true
You can say (light as any).isSpotLight, but without the cast, you get the red squigglies no matter what you compare it to.
Here's a stackblitz playground so you can try it: https://stackblitz.com/edit/typescript-2ug1rc
I don't think this scales...
Next you'll want to test mesh.isSpotLight and we'll have to add all the booleans in the API to all the classes.
It's a good point. So in a typescript world, the isXXX props are not that useful.
Right now, as I'm recursing through the scene, I'm using if (obj.type === 'Group') ... (or Scene or Object3D or PointLight or whatever) which works, but I was a bit unsure about that because obj.type is undocumented. I thought the specific props might be better since they're documented.
Actually perhaps a better way is just to say if (light instanceof Three.SpotLight) .... That seems to work (I just tried it in that stackblitz). It's probably faster too.
I'll close this now. If you think it's worth documenting something about this, let me know and I'll be happy to write up something.
Yes, light instanceof THREE.SpotLight is probably the way to go in your case. However, be aware that we used that approach in core before but replaced it with the booleans to allow better tree-shaking.
@garyo the issue here is partly with the types and partly with how you鈥檙e narrowing the types. Attempting to directly access the potentially undefined property results in the type error you鈥檙e encountering. You鈥檒l want to use the in keyword instead.
If light is of type PointLight | SpotLight, the type of light can be narrowed to one or the other by checking for the property like so:
if ('isSpotLight' in light) {
// inside this block, `light` is known to be of type `SpotLight`
}
However, if light is of type Light, it cannot be narrowed since it is the supertype, not a union of subtypes.
A potential snag: it looks like the SpotLight/PointLight type definitions don鈥檛 have those is* booleans defined though, so narrowing with those booleans will not be possible. However you can check for other unique properties鈥攆or example, SpotLight type defs specify a penumbra type, so 'penumbra' in light will narrow to every type of Light that has a 'penumbra' prop.
Thanks @meyer but I think the light instanceof THREE.SpotLight etc. is the cleanest solution in my case.
If the GLTFExporter sample is ever converted to Typescript it'll probably want to use the same technique in its processLight method. In cases like this no tree-shaking is possible anyway, since at runtime any subclass could be present.