Removing Generics from Meshes causes a lot of headaches

Describe the bug

For some context, i’m using react-three-fiber. My use case is when i’m loading a GLTF model, to TS it’s a black box, So I know it’s a mesh & can typecast the return of the gltf to be Mesh. However, when I want to edit the properties of the mesh materials, I now have to typecast the material because Mesh is no longer a generic. This is quite a headache. I’m not saying i’m right, it’d be good to get some clarity on why this commit was done?

Old Code

type GLTFResult = GLTF &
  ObjectMap & {
    nodes: {
      [name: string]: Mesh<BufferGeometry, MeshStandardMaterial>
    }
  }

  const { nodes } = useGLTF(
    `${ENV_MODEL_PATH}/rain/RainPond_Droplets_Polyredux.gltf`
  ) as GLTFResult

  const instanceMeshes = React.useMemo(
    () =>
      meshes
        .filter((mesh) => mesh.material)
        .map((mesh, i) => {
          mesh.material.metalness = 0 // all good here, no typecast needed
          mesh.material.transparent = true
          mesh.material.onBeforeCompile = compileMaterialForInstance

          mesh.geometry.setAttribute(
            'instOpacity',
            new InstancedBufferAttribute(
              new Float32Array(new Array(INSTANCE_COUNT).fill(0)),
              1
            )
          )

          return (
            <instancedMesh
              ref={(ref: THREE.InstancedMesh) =>
                setKeyValue(instanceRefs.current, i, ref)
              }
              key={mesh.name}
              args={[mesh.geometry, mesh.material, INSTANCE_COUNT]}
            />
          )
        }),
    [meshes]
  )

New Code

type GLTFResult = GLTF &
  ObjectMap & {
    nodes: {
      [name: string]: Mesh
    }
  }

  const { nodes } = useGLTF(
    `${ENV_MODEL_PATH}/rain/RainPond_Droplets_Polyredux.gltf`
  ) as GLTFResult

  const instanceMeshes = React.useMemo(
    () =>
      meshes
        .filter((mesh) => mesh.material)
        .map((mesh, i) => {
          mesh.material.metalness = 0 // this now throws an error because metalness does not exist on type Material[]
          mesh.material.transparent = true
          mesh.material.onBeforeCompile = compileMaterialForInstance

          mesh.geometry.setAttribute(
            'instOpacity',
            new InstancedBufferAttribute(
              new Float32Array(new Array(INSTANCE_COUNT).fill(0)),
              1
            )
          )

          return (
            <instancedMesh
              ref={(ref: THREE.InstancedMesh) =>
                setKeyValue(instanceRefs.current, i, ref)
              }
              key={mesh.name}
              args={[mesh.geometry, mesh.material, INSTANCE_COUNT]}
            />
          )
        }),
    [meshes]
  )

Expected behavior

Ideally i’d like to pass the Generics back in, because even if it was able to figure out if it was Material or Material[] I know the material is MeshStandardMaterial so metalness will still throw a typescript error.

disclaimer
I’m happy to work on a solution if we want to fix this.

Platform:

  • Three.js version: r125

1 possible answer(s) on “Removing Generics from Meshes causes a lot of headaches

  1. I suppose if someone fixes something they should surely update the .d.ts file at the same time?

    And that’s how you force JavaScript people learn TypeScript. Makes contributing harder.

    I’m not liking this at all.