0
点赞
收藏
分享

微信扫一扫

ts使用装饰器 !!要注意⚠️


以下,是一个错误示范 因为装饰器的修饰,函数的返回类型与实际返回的不符,导致要强制断言类型,否则无法享受ts自动推断类型的便利,导致越写越繁琐,失去了写ts的意义。

由此,在书写前就应当设计好函数和装饰器的分功,这并非是使用装饰器的代价,而是要求我们以一种更好的设计模式来书写代码,从这点考虑使用装饰器是有更深远的收益的。而非一个封装函数能替代的

/*
 * @Author: hongbin
 * @Date: 2023-08-27 17:45:43
 * @LastEditors: hongbin
 * @LastEditTime: 2023-08-27 19:45:41
 * @Description: 便捷创建mesh
 */
import * as THREE from "three";

type CreateGeo<
    T extends THREE.BufferGeometry = THREE.BufferGeometry,
    M extends THREE.Material = THREE.Material
> = (...args: any[]) => THREE.Mesh<T, M>;

type DecorateBack<T extends THREE.BufferGeometry = THREE.BufferGeometry> = {
    mesh: ReturnType<CreateGeo<T>>;
    material: (m: THREE.Material) => void;
};

type CreateMesh = (...args: Parameters<CreateGeo>) => DecorateBack;

type Extract<T extends abstract new (...args: any) => any> =
    ConstructorParameters<T>;

const meshDecorate: MethodDecorator = (t, k, d) => {
    const prev = <CreateGeo>d.value;
    (<CreateMesh>d.value) = function (...args: any[]) {
        const mesh = prev.call(this, ...args);
        return {
            mesh,
            material: (material: THREE.Material) => {
                mesh.material = material;
            },
        };
    };
};

export class Create {
    static defaultMaterial = new THREE.MeshStandardMaterial({
        color: new THREE.Color("#51f"),
    });

    @meshDecorate
    static plane(...args: Extract<typeof THREE.PlaneGeometry>) {
        const planeGeo = new THREE.PlaneGeometry(...args);

        return new THREE.Mesh(
            planeGeo,
            Create.defaultMaterial
        ) as unknown as DecorateBack<THREE.PlaneGeometry>;
    }
}

改良后

/*
 * @Author: hongbin
 * @Date: 2023-08-27 17:45:43
 * @LastEditors: hongbin
 * @LastEditTime: 2023-08-27 23:55:20
 * @Description: 便捷创建mesh
 */
import * as THREE from "three";

export class Create {
    private static defaultMaterial = new THREE.MeshStandardMaterial({
        color: new THREE.Color("#51f"),
    }) as THREE.Material;

    private static _temp: {
        mesh: THREE.Mesh<THREE.BufferGeometry, THREE.Material>;
        material: (material: THREE.Material) => void;
    };

    private static callbackTemp<T extends THREE.BufferGeometry>() {
        return {
            mesh: Create._temp.mesh as THREE.Mesh<T, THREE.Material>,
            material: Create._temp.material,
        };
    }

    @Create.geometry(THREE.PlaneGeometry)
    static plane(...args: ConstructorParameters<typeof THREE.PlaneGeometry>) {
        return Create.callbackTemp<THREE.PlaneGeometry>();
    }

    @Create.geometry(THREE.BoxGeometry)
    static box(...args: ConstructorParameters<typeof THREE.BoxGeometry>) {
        return Create.callbackTemp<THREE.BoxGeometry>();
    }

    /**
     * 几何体装饰器
     * 返回mesh和修改material的方法,以后可以拓充更多方法
     */
    private static geometry = (
        geometry: typeof THREE.BufferGeometry
    ): MethodDecorator => {
        return function (t, k, d) {
            const prev = <typeof Create.plane>d.value;
            (d.value as any) = (
                ...args: ConstructorParameters<typeof geometry>
            ) => {
                Create.handleGeometry(geometry, ...args);
                return prev.call(Create);
            };
        };
    };

    /**
     * geometry装饰器 内部的实现
     */
    private static handleGeometry = (
        geometry: typeof THREE.BufferGeometry,
        ...args: ConstructorParameters<typeof geometry>
    ) => {
        const geo = new geometry(...args);
        const mesh = new THREE.Mesh(geo, Create.defaultMaterial);
        Create._temp = {
            mesh,
            material: (material: THREE.Material) => {
                mesh.material = material;
            },
        };
    };
}


举报

相关推荐

0 条评论