在类型定义文件中定义类型与在普通类型文件中定义类型的优点

Bag*_*ong 7 types typescript redux react-redux

对于应用程序代码,是否建议将 Redux 存储类型放在state-slice.d.ts文件中?

\n

我继承了一个代码库,其中所有核心类型都放置在.d.ts定义文件中,但这与我\xe2\x80\x99ve 理解定义文件的作用的方式相反。

\n

我的理解是,定义文件适用于您\xe2\x80\x99编写库时(这是作者集中接口来定义我们向消费者公开的库的API的一个方便的地方),但不适合对于应用程序代码,因为数据可能会快速变化。

\n

也就是说,我\xe2\x80\x99无法对.d.ts文件本身提出一个很好的论据 - 从功能的角度来看,我不\xe2\x80\x99t看到引用类型的区别

\n
declare namespace Domain {\n  interface State {\n    // ...\n  }\n} \n
Run Code Online (Sandbox Code Playgroud)\n

从定义文件中,或从具有以下内容的文件中显式导入文件

\n
export interface ReduxState {}\n
Run Code Online (Sandbox Code Playgroud)\n

添加更多上下文,因为这是一个有点特殊的问题 - I\xe2\x80\x99m 目前正在开发一个新项目,该项目需要从我继承的现有代码库中共享这些核心类型,并且 I\xe2\x80\ x99m 尝试将这些类型移至单独的包中。

\n

不幸的是,我\xe2\x80\x99在导入和导出这些类型时遇到了问题 - 似乎我必须(注意 s export

\n
/* package A */\nexport declare namespace StateA { }\n\n/* package B */\nimport { StateA } from 'packageA/StateA' \n\nconst stateA: StateA = {};\n
Run Code Online (Sandbox Code Playgroud)\n

而不是 TypeScript 自动拾取它。

\n
/* package B (originally) */\n\n// stateA.d.ts\ndeclare namespace StateA {}\n\n// test.ts\nconst stateA: StateA = {};\n
Run Code Online (Sandbox Code Playgroud)\n

我\xe2\x80\x99尝试更改文件typeRoots中的字段tsconfig.json,看看是否可以避免import在各处插入语句,但无济于事。

\n

我想这可能是一个将所有类型定义文件转换为普通类型文件的好机会,但除了“我不认为我们应该使用类型定义文件”和“我可以\xe2\x80\x99t 使定义类型中的类型像现在一样工作”。

\n

所以我的问题是

\n
    \n
  • 与在普通文件中定义类型相比,使用类型定义文件有哪些好处.ts
  • \n
  • 在使用面向消费者的应用程序代码时,我们是否应该编写自己的定义文件?
  • \n
  • 是不是我想太多了,真的没关系吗?
  • \n
\n

如果这个问题有点开放式,我提前表示歉意,我希望这不是不适合 StackOverflow 社区(或者如果不适合,请问什么论坛比较合适?)。谢谢!

\n

cbd*_*per 4

您是否看过这个答案How do I use namespaces with TypeScript external module?

我不完全同意,但我认为值得一看。我最近也问了我所有这些问题。

这是我一直在做的事情:

对于仅在一个文件或几个文件中使用的类型,我从常规ts文件中定义和导出它们。

例如:

商店.ts

该文件定义了一个APP_THUNK仅由少数处理 redux thunk 创建的文件使用的类型。因此,我正在定义并从此文件导出,因为它使用ROOT_STATE也在此处定义的类型。

import { configureStore } from "@reduxjs/toolkit";
import { rootReducer } from "./rootReducer";
import { Action } from "@reduxjs/toolkit";
import { ThunkAction } from "redux-thunk";

export interface ROOT_STATE {
  ...
}

export type APP_THUNK = ThunkAction<
  Promise<void> | void,
  ROOT_STATE,
  unknown,
  Action<string>
>

export const store = configureStore({
  reducer: rootReducer
});
Run Code Online (Sandbox Code Playgroud)

然后,当我需要使用这些类型时,我导入它们:import { APP_THUNK } from "@redux/store";

但我也有一些类型在我的整个项目的许多文件中使用。对于这些类型,我保留d.ts文件并通过使用declare namespace SOME_NAMESPACE.

例如:

博客文章.d.ts

该文件定义了与blogPost对象相关的所有类型。

declare namespace PROJECT {

  interface BLOGPOST {
    id: string,
    slug: string,
    images: BLOGPOST_IMAGE[]
  }

  interface BLOGPOST_IMAGE {
    id:        string,
    src:       string,
    alt:       string,
    caption:   string,
  }

  // AND SO ON...
  // THERE ARE MANY MORE TYPES HERE RELATED TO BLOGPOSTS  

}
Run Code Online (Sandbox Code Playgroud)

我还合并了PROJECT不同文件中的命名空间。例如:PRODUCTS.d.tsalso 声明namespace PROJECT并自动与 上的声明合并BLOGPOSTS.d.ts

使用这些类型非常方便:

interface Props {
  blogPost: PROJECT.BLOGPOST
}

// OR MAYBE

const blogPost = await API.getBlogPost() as PROJECT.BLOGPOST;
Run Code Online (Sandbox Code Playgroud)

自动完成会立即分组到该命名空间下。我认为这也很好。

在此输入图像描述

这对我有用。请考虑到我是单独工作,并且这种类型仅在这个项目中使用。不知道这种模式是否适用于多人团队或跨不同项目。

另请注意,在 Typescript官方文档中,我们得到:

使用模块

模块可以包含代码和声明。

模块还依赖于模块加载器(例如 CommonJs/Require.js)或支持 ES 模块的运行时。模块提供更好的代码重用、更强的隔离和更好的捆绑工具支持。

还值得注意的是,对于 Node.js 应用程序,模块是默认设置,我们建议在现代代码中使用模块而不是命名空间。

从 ECMAScript 2015 开始,模块是该语言的本机部分,并且应该受到所有兼容引擎实现的支持。因此,对于新项目,模块将是推荐的代码组织机制。

但我仍然认为,当您使用这些类型时,当您在模块上使用命名空间时,这是一种更好的开发体验。但要注意名称空间冲突,因为它们是全局的。