Argument of type 'Nullable<AbstractMesh>' is not assignable to parameter of type

305 阅读2分钟

学习BabylonJS,编写开关运行,报以下错误

import { Engine, Scene, ArcRotateCamera, Vector3, HemisphericLight, SpriteManager, Sprite, MeshBuilder, StandardMaterial, Texture, Color3, SceneLoader, CubeTexture, Mesh, ParticleSystem, Color4, PointerInfo, PointerEventTypes } from "@babylonjs/core";
import "@babylonjs/loaders";
import { CreateSceneClass } from "../createScene";

export class SpriteTrees implements CreateSceneClass {
    createScene = async (
        engine: Engine, 
        canvas: HTMLCanvasElement
    ) : Promise<Scene> => {
        const scene = new Scene(engine);
        this.showDebug(scene);
        const arcRotateCamera = new ArcRotateCamera("arcRotateCamera", -Math.PI / 2, Math.PI / 2.5, 15, new Vector3(0, 0, 0), scene);
        arcRotateCamera.upperBetaLimit = Math.PI / 2.2;
        arcRotateCamera.attachControl(canvas, true);
        const hemisphericLight = new HemisphericLight("hemisphericLight", new Vector3(1, 1, 0), scene);

//Swith fountain on and off
        let switched = false;
        const pointerDown = (mesh : Mesh) => {
            if (mesh === fountain) {
                switched = ! switched;
                if(switched) {
                    // Start the particle system
                    particleSystem.start();
                } else {
                    // Stop the particle system
                    particleSystem.stop();
                }
            }
        }
        scene.onPointerObservable.add((pointerInfo : PointerInfo) => {
            switch (pointerInfo.type) {
                case PointerEventTypes.POINTERDOWN:
                    if (pointerInfo.pickInfo?.hit) {
                            pointerDown(pointerInfo.pickInfo.pickedMesh);
                    }
                    break;
            }
        });
   SceneLoader.ImportMeshAsync("",  "https://assets.babylonjs.com/meshes/", "valleyvillage.glb");
        return scene;
    };
export default new SpriteTrees();

运行显示如下:

ERROR in /***/***/***.ts(35,41)
      TS2345: Argument of type 'Nullable<AbstractMesh>' is not assignable to parameter of type 'Mesh'.
  Type 'null' is not assignable to type 'Mesh'.

该错误提示的意思是正在尝试将 pointerInfo.pickInfo.pickedMesh 作为参数传递给 pointerDown 函数,但是该函数期望接收的参数类型是 Mesh,而 pointerInfo.pickInfo.pickedMesh 的类型是 Nullable<AbstractMesh>,即可为空的抽象网格类型,这意味着可能存在传递 null 的情况,而 null 无法分配给 Mesh 类型。

为了解决这个问题,可以使用类型断言来确保传递的参数是 Mesh 类型而不是可为空的抽象网格类型。具体来说,您可以这样写:

pointerDown(pointerInfo.pickInfo.pickedMesh as Mesh);

使用 as 关键字将 pointerInfo.pickInfo.pickedMesh 显式地强制转换为 Mesh 类型,这样即使其为空,也不会引起类型错误。

总结

TypeScript基础掌握不足,对as 关键字不熟悉,下面让我们看下as关键字相关知识:

在 TypeScript 中,使用 as 关键字可以进行类型断言,即将某个值强制转换成特定的类型。类型断言有两种形式,一种是尖括号语法,一种是 as 语法。

尖括号语法的形式如下:

let str: any = '123';
let num: number = (<string>str).length;

as 语法的形式如下:

let str: any = '123';
let num: number = (str as string).length;

as 语法与尖括号语法相比,更加易读和不容易出错。但是需要注意的是,as 语法只能用于将某个值转换成更具体的类型或者相互兼容的类型,否则会导致编译错误。

下面是一个实例,假设我们有一个对象数组,数组中的每个对象都有一个 name 属性,但是这个属性可能是字符串类型,也可能是 undefined。我们想要将这个属性全部转换成字符串类型,并且去掉空字符串。

interface User {
  name?: string;
  age: number;
}

const users: User[] = [
  { name: 'Alice', age: 18 },
  { name: undefined, age: 20 },
  { name: '', age: 22 },
];

const names: string[] = users.map((user) => user.name)
  .filter((name) => name !== undefined && name !== '')   // 过滤掉 undefined 和空字符串
  .map((name) => name as string);      // 将 name 强制转换成 string 类型
console.log(names);       // ['Alice']

在上面的例子中,我们使用了 as 语法将 name 属性强制转换成了 string 类型,然后过滤掉了 undefined 和空字符串。