Ged*_*sFX 7 extend user-data three.js typescript .d.ts
在 Three.js 中,类上有一个Object3D名为 userData 的字段,它在类型声明文件中node_modules/three/src/core/Object3D.d.ts定义为
/**
* Base class for scene graph objects
*/
export class Object3D extends EventDispatcher {
[...]
/**
* An object that can be used to store custom data about the Object3d. It should not hold references to functions as these will not be cloned.
* @default {}
*/
userData: { [key: string]: any };
[...]
}
Run Code Online (Sandbox Code Playgroud)
我想对 userData 进行更强的类型化,因此我创建了一个模块类型声明src/typings/three.d.ts:
declare module 'three' {
export class Object3D {
userData: MyType1 | MyType2;
}
}
type MyType1 = {
type: 'type1';
radius: number;
};
type MyType2 = {
type: 'type2';
name: string;
};
Run Code Online (Sandbox Code Playgroud)
虽然它确实覆盖了该userData属性,但它不是合并,而是覆盖了three模块中的所有类型声明,使得更改的破坏性大于有用性(请注意缺少其他属性)。

有没有办法以仅 userData覆盖而不覆盖整个模块的方式合并类型声明?
用打字稿术语来说,您要做的是“声明合并”与“模块增强”相结合(请参阅文档)。到目前为止,您的示例存在一些问题,其中大多数是可以修复的,其中之一则不可修复(即您遇到了语言的限制)。
我将首先解释这些问题和(部分)解决方案,然后提出一种完全可行的替代方法。
export class Object3D你必须写成interface Object3D. (我知道,这不是最直观的事情 - 但文档指出“TypeScript 中并非允许所有合并。目前,类不能与其他类或变量合并。”)extends语句。所以而不是...
interface Object3D {
Run Code Online (Sandbox Code Playgroud)
……你需要写……
interface Object3D<E extends BaseEvent> extends EventDispatcher<E> {
Run Code Online (Sandbox Code Playgroud)(向之前的答案
致敬,指出了这个记录不足的“陷阱”)@types/three,它不仅仅是一个顶层带有“export class Object3D...”类型语句的大文件。相反,根文件中@types/three有这样的语句:
export * from './src/Three';
Run Code Online (Sandbox Code Playgroud)
反过来,src/Three(除其他外)有这样的声明:
export * from './core/Object3D';
Run Code Online (Sandbox Code Playgroud)
最后src/core/Object3D有核心类定义:
export class Object3D<E extends BaseEvent = Event> extends EventDispatcher<E> {
Run Code Online (Sandbox Code Playgroud)
我通过实验发现(尽管我找不到明确的解释),这些中间export *语句妨碍了模块增强代码实际上与它试图影响的事物相匹配(例如Object3D中的类定义@types/three/src/core/Object3D) 。为了解决这个问题,您的declare module语句必须专门针对该文件,而不是它的重新导出版本。所以把所有这些放在一起,这(几乎)会起作用:
import { BaseEvent, EventDispatcher } from "three";
declare module "three/src/core/Object3D" {
interface Object3D<E extends BaseEvent> extends EventDispatcher<E> {
// This works fine...
somethingElse: string;
// However, this does not (see below)
// Typescript will throw this error:
// Subsequent property declarations must have the same type. Property 'userData' must be of type '{ [key: string]: any; }'
userData: MyType1 | MyType2;
}
}
Run Code Online (Sandbox Code Playgroud)
最后一个问题是语言的限制 - 声明合并无法更改原始类定义上现有属性的类型(即使新类型在技术上是原始类型的子类型)。它只能向类添加新属性。
一种可行的替代方法
您可以创建一个扩展原始类的新类声明,并覆盖其中的类型,而不是使用声明合并:
declare module "three" {
import { BaseEvent } from "three/src/core/EventDispatcher";
import { Object3D as Object3DOriginal } from "three/src/core/Object3D";
export * from "three/src/Three";
export class Object3D<E extends BaseEvent = Event> extends Object3DOriginal<
E
> {
userData: MyType1 | MyType2;
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
843 次 |
| 最近记录: |