我对typescript非常陌生,我正在为WebGl编写一个小型原型框架.我目前正在重构我的项目,遇到了一些问题,比如如何组织我的项目,因为(模块和名称空间)方法似乎都有严重的缺陷.

This post is not about HOW to use these patterns, but how to overcome the problems each of these brings.

Status Quo: Using namespaces

来自C#这似乎是最自然的方式.每个类/模块都会得到相应的名称空间,我在tsconfig中提供"outFile"参数.json,因此所有内容都被连接到一个大文件中.

示例文件

namespace Cross.Eye {
    export class SpriteFont {   
        //code omitted
    }    
}

用法示例(在html中提供js文件之前,必须确保跨命名空间加载到全局命名空间中)

namespace Examples {
    export class _01_BasicQuad {
        context: Cross.Eye.Context;
        shader: Cross.Eye.ShaderProgram;

        //code omitted
    }
}

赞成的意见

  • 如果你是从C#/Java提交,使用起来很简单
  • 与文件名无关——重命名文件不会 destruct 代码.
  • 易于重构:IDE可以很容易地重命名名称空间/类,这些更改将在整个代码中得到一致的apply.
  • 便利性:向项目中添加一个类非常简单,只需添加一个文件并在所需的命名空间中声明即可.

欺骗

对于大多数项目,我们建议使用外部模块和名称空间进行快速演示,并移植旧的JavaScript代码.

https://basarat.gitbooks.io/typescript/content/docs/project/namespaces.html

  • 根命名空间总是(?)全局对象(坏)
  • 不能(?)可以与browserify或webpack等工具一起使用,这对于将库与其依赖项Bundle 在一起或在实际使用时将自定义代码与库Bundle 在一起是必不可少的.
  • 如果你计划发布一个npm模块,这是错误的做法

State of the art (?): Modules

Typescript支持ES6模块,它们是新的和shiny 的,每个人似乎都同意它们是future 的发展方向.其 idea 似乎是,每个文件都是一个模块,通过在import语句中提供这些文件,您可以非常明确地定义依赖项,这使得Bundle 工具能够轻松有效地打包代码.我通常每个文件都有一个类,这似乎不适合dhte模块模式.

这是我重构后的文件 struct :

在此处输入图像描述

我还有一个索引.每个文件夹中都有一个ts文件,这样我就可以在import * as FolderModule from "./folder"之前导入它的所有类

export * from "./AggregateLoader";
export * from "./ImageLoader";
export * from "./TiledLoader";
export * from "./XhrLoaders";
export * from "./XmlSpriteFontLoader";

示例文件 - I think the problem becomes clearly visible here..

import {SpriteFont} from "./SpriteFont";
import {ISpriteTextGlyph, ISpriteChar} from "./Interfaces";
import {Event,EventArgs} from "../../Core";
import {Attribute, AttributeConfiguration} from "../Attributes";
import {DataType} from "../GlEnums";
import {VertexStore} from "../VertexStore";
import {IRectangle} from "../Geometry";
import {vec3} from "gl-matrix";

export class SpriteText {
    // code omitted
}

示例用法.如您所见,我不再需要遍历名称空间,因为我可以直接导入类.

import {
    Context,
    Shader,
    ShaderProgram,
    Attribute,
    AttributeConfiguration,
    VertexStore,
    ShaderType,
    VertexBuffer,
    PrimitiveType
} from "../cross/src/Eye";

import {
    Assets,
    TextLoader
} from "../cross/src/Load";

export class _01_BasicQuad {
    context: Context;
    shader: ShaderProgram;

    // code omitted.
}

赞成的意见

  • 使代码更加模块化,因为它不再绑定到名称空间.
  • 您可以使用browserfy或webpack等Bundle 工具,它们也可以Bundle 所有依赖项
  • 导入类时更加灵活,不再需要遍历名称空间链.

欺骗

  • 如果每个类都是不同的文件,那么就必须反复输入相同的导入语句.
  • 重命名文件会 destruct 代码(错误).
  • 重构类名不会传播到您的导入中(非常糟糕——可能取决于您的IDE,我使用的是vs代码)

这两种方法似乎都有缺陷.名称空间似乎非常过时,不适用于大型项目,与常用工具不兼容,而使用模块非常不方便,并且 destruct 了我最初调整typescript的一些功能.

在一个完美的世界里,我会使用名称空间模式编写我的框架,并将其导出为一个模块,然后可以将其导入并与其依赖项Bundle 在一起.然而,如果没有一些丑陋的黑客,这似乎是不可能的.

所以我的问题是:你是如何处理这些问题的?如何最大限度地减少每种方法的缺点?

Update

在获得了更多关于typescript和javascript开发的经验之后,我必须指出,模块可能是所有用例中90%的使用方法.

最后10%希望是使用全局名称空间的遗留项目,您希望用一点typescript(顺便说一句,它非常有效)来增加这些项目的趣味性.

我对模块的许多批评可以(并且已经)通过更好的IDE支持来解决.Visual Studio代码添加了自动模块解析功能,效果非常好.

推荐答案

tl;dr: Do not choose the past. Choose the future: Modules.

在ES6模块规范的早期草案中,有一个inline modules的概念,然后是has been eliminated in September 2013.然而,这个概念已经在2012年由TypeScript团队实现,该语言的第一个beta版本是internal modules.然后,没有内联模块的ES6模块的最终规范是has been released in July 2014.一年后的2015年7月,为了避免与标准混淆,TypeScript的1.5版本从internal modules has been renamednamespaces.

名称空间是一个遗留特性.它不会成为ECMAScript语言的一部分.TypeScript团队将继续遵循标准.自2014年7月ECMAScript模块标准发布以来,TS名称空间没有任何改进.

【ES6模块的缺点】

  • 如果每个类都是不同的文件,那么就必须反复输入相同的导入语句.
  • 重命名文件会 destruct 代码(错误).
  • 重构类名不会传播到您的导入中(非常糟糕——可能取决于您的IDE,我使用的是vs代码)

我们希望future 的IDE能在这些问题上有所改进.第一个问题已经由WebStorm解决.

Typescript相关问答推荐

如何使用Generics保留构造函数的类型信息?

如何将绑定到实例的类方法复制到类型脚本中的普通对象?

使用React处理Websocket数据

HttpClient中的文本响应类型选项使用什么编码?''

如何提取密钥及其对应的属性类型,以供在新类型中使用?

无法从Chrome清除还原的初始状态数据

返回具有递归属性的泛型类型的泛型函数

如何判断对象是否有重叠的叶子并产生有用的错误消息

在函数中打字推断记录的关键字

是否存在类型联合的替代方案,其中包括仅在某些替代方案中存在的可选属性?

是否将自动导入样式从`~/目录/文件`改为`@/目录/文件`?

NPM使用Vite Reaction应用程序运行预览有效,但我无法将其部署到Netlify

如何在打字角react 式中补齐表格组

埃斯林特警告危险使用&as";

两个名称不同的相同打字界面-如何使其干燥/避免重复?

为什么`map()`返回类型不能维护与输入相同数量的值?

如何使对象同时具有隐式和显式类型

为什么我会得到一个;并不是所有的代码路径都返回一个值0;switch 中的所有情况何时返回或抛出?(来自vsCode/TypeScript)

基于可选参数的动态类型泛型类型

类型string不可分配给类型string| 联盟| 的'