以下,是一个错误示范 因为装饰器的修饰,函数的返回类型与实际返回的不符,导致要强制断言类型,否则无法享受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;
},
};
};
}