gpt4 book ai didi

typescript - 在手写的 d.ts 文件中,如何从模块根目录中的一个命名空间公开函数?

转载 作者:行者123 更新时间:2023-12-03 17:09:01 25 4
gpt4 key购买 nike

我正在开发一个全部在 javascript 中但导出手写类型声明 (automerge/index.d.ts) 的 repo。
代码库的结构是它有一个前端和一个后端,加上一个提供自己的便利功能的公共(public) API,此外还直接从前端和后端重新导出一些功能。
像这样的东西:

declare module `foo` {

// functions that only exist in the public API
function a
function b
function c

// functions exposed directly from namespace A
function q
function r
function s

// functions exposed directly from namespace B
function x
function y
function z

namespace A {
function q
function r
function s
function t
}

namespace B {
function v
function w
function x
function y
function z
}

}
这是实际代码的摘录,显示了我们当前如何为重新导出的函数编写重复声明。
declare module 'automerge' {
...

function getObjectById<T>(doc: Doc<T>, objectId: OpId): Doc<T>

namespace Frontend {
...

function getObjectById<T>(doc: Doc<T>, objectId: OpId): Doc<T>
}

...
}
有没有办法避免两次编写这些声明?

最佳答案

我认为您正在寻找的东西不能通过命名空间实现。但是命名空间是 Typescript 早期的遗留功能,并且(强烈)不鼓励使用它们 - from official docs :

[...] we recommended modules over namespaces in modern code.


不久又一次:

Thus, for new projects modules would be the recommended code organization mechanism.


在提供类型定义的情况下,删除命名空间的使用应该相对简单。
最简单的选择是通过直接声明它们的类型来声明导出的对象。如果是 Frontend它看起来像这样:
const Frontend: {
// in the main scope & Frontend
// redeclared with typeof
change: typeof change;
emptyChange: typeof emptyChange;
from: typeof from;
getActorId: typeof getActorId;
getConflicts: typeof getConflicts;
getLastLocalChange: typeof getLastLocalChange;
getObjectById: typeof getObjectById;
getObjectId: typeof getObjectId;
init: typeof init;

// in Frontend only
// declaration from scratch
applyPatch<T>(
doc: Doc<T>,
patch: Patch,
backendState?: BackendState
): Doc<T>;
getBackendState<T>(doc: Doc<T>): BackendState;
getElementIds(list: any): string[];
setActorId<T>(doc: Doc<T>, actorId: string): Doc<T>;
};

以上内容并不理想,因为您需要输入两次导出的函数名称,这很容易出错,但对于您处理的类型数量可能完全没问题。
另一种选择是使用辅助模块首先将相关功能组合在一起,然后从辅助模块重新导出它们并从主模块重新导入:
declare module "automerge/frontend" {
export {
change,
emptyChange,
from,
getActorId,
getConflicts,
getLastLocalChange,
getObjectById,
getObjectId,
init
} from "automerge";
import { Doc, Patch, BackendState } from "automerge";

export function applyPatch<T>(
doc: Doc<T>,
patch: Patch,
backendState?: BackendState
): Doc<T>;
export function getBackendState<T>(doc: Doc<T>): BackendState;
export function getElementIds(list: any): string[];
export function setActorId<T>(doc: Doc<T>, actorId: string): Doc<T>;
}

declare module "automerge" {
/* other stuff */
import * as _Frontend from 'automerge/frontend'
const Frontend: typeof _Frontend
/* other stuff */
}

由于 import/export 的循环性质,上述内容有点令人费解且相当不雅。您可以尝试将所有相关功能移至 module "automerge/frontend" ,但是您需要从那里重新导出它们,这将稍微改变语义,并且所有导出都需要明确(以 export 关键字为前缀 - 例如: export type Doc<T> = FreezeObject<T>; )。

作为最正确和面向 future 的解决方案,我可以建议将代码重构为没有任何循环依赖关系的模块——可能需要创建一个通用模块来对共享类型进行分组。
顺便提一句。如果您对上述任何选项感兴趣,请告诉我,我很乐意创建一个 PR,我们可以在那里进行讨论。

关于typescript - 在手写的 d.ts 文件中,如何从模块根目录中的一个命名空间公开函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67488737/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com