我已经和Typescipt一起工作了几个月,这方面已经在几个项目的过程中让我烦恼了.假设我有以下项目结构:
project
+- app
| +- component1
| | +- component1.ts
| +- component2
| | +- component2.ts
| +- utils
| +- utils.ts
+- tsconfig.json
Run Code Online (Sandbox Code Playgroud)
现在,假设utils.ts文件包含许多辅助类(例如数据结构)甚至可能包含全局函数,并且项目中的几乎每个其他文件至少使用其中的一部分.如何使用最少量的样板代码?
使用import语句
// utils.ts
export function foo() { return 1; }
// component1.ts
import { foo, bar, baz, ...(a long list here) } from '../utils/utils'
let x = foo(); // looks fine
Run Code Online (Sandbox Code Playgroud)
优点:进口会员使用简单
缺点:几乎每个其他文件都需要维护长导入列表
另一个选择是一次导入所有内容:
// component1.ts
import * as utils from '../utils/utils' // I have to remember to put this line on top of every other file, but it's better than the option above
let x = utils.foo(); // unavoidable prefixes all over the code
Run Code Online (Sandbox Code Playgroud)
优点:import语句是通用的,可以复制到每个文件只改变相对路径(虽然如果有一种方法可以隐式地在项目范围内这样做,我会更高兴)
缺点:代码中的简单帮助函数的名称空间前缀.由于某种原因,Typescript不允许在import *没有显式命名空间的情况下使用.
使用triple-slash指令
// utils.ts
function foo() { return 1; } // no export keyword
// component1.ts
/// <reference path="../utils/utils.ts" />
let x = foo();
Run Code Online (Sandbox Code Playgroud)
即使我仍然需要在每个文件的顶部指定具有相对路径的引用,这看起来要好得多.但是,当我尝试将我的应用程序与webpack捆绑在一起时,它完全打破了 - utils.js只是没有与应用程序的其余部分捆绑在一起(我想这是另一个SO问题的主题).
我真的想就是用我的代码在utils.ts的能力,像我使用全局库类- ,Map,Set,HTMLElement,Promise等,没有任何进口或前缀,有没有什么办法来实现这一目标?
PS请注意,我早就放弃了实际将我的utils.ts分成多个文件(每个类/全局函数一个)的良好编程原则,因为它会大大加剧上面的问题.我实际上已经在考虑为整个项目使用单个文件了.
当你这样做时/// <reference path="../utils/utils.ts" />,你告诉 Typescript 编译器的是“utils.ts 模块中的所有内容都在全局范围内”。Typescript 不会做任何事情来真正实现这一点,你只是告诉 TS 它已经完成了,并且它相信你。(例如,如果您<script src="..">在 HTML 中加载了带有标签的库以全局加载库,则可以使用此注释来告诉 Typescript 相关信息。)
如果你想走这条路,你需要注释来告诉打字稿 utils 在全局范围内,但你还需要在某个地方实际添加逻辑来实现这一点。Webpack 有多种定义全局变量的方法,但一种选择是使用global,在应用程序开头的某个位置使用如下代码:
import * as utils from "../path/to/utils";
for(const key in utils) {
global[key] = utils[key];
}
Run Code Online (Sandbox Code Playgroud)
现在,实际上,所有 utils 都在全局范围内,并且引用路径注释会通知 Typescript,因此 Typescript 很高兴。
但是,老实说,我不能说我建议在实践中这样做。污染全局范围是一种非常经典的反模式,通常会使程序难以遵循。任何阅读你的代码的人都会看到“神奇”的功能,例如foo似乎凭空出现,并且没有任何迹象表明该函数来自何处。而且,与全局范围的所有添加一样,它为名称冲突打开了大门。
就我个人而言,我建议只进行标准导入:就我个人而言,我倾向于import { foo } from "utils/utils",尽管有时utils.foo更容易理解(例如,如果其他一些之间存在命名冲突)foo我导入的模块中的其他模块之间存在命名冲突)。
通过 TS 和 webpack 的一些配置,您可以像这样编写导入
import * as utils from 'utils/utils'
Run Code Online (Sandbox Code Playgroud)
代替:
import * as utils from '../../utils/utils'
Run Code Online (Sandbox Code Playgroud)
相关的配置部分位于"include"tsconfig 和"resolve.modules"webpack 配置中。(或者resolve.root如果您使用的是 webpack 1.0)在您的情况下,您需要将“app”添加到这两个列表中,以指示“app”是源文件的根目录。
通过一致的导入路径,如果您有很多经常使用的导入,您可以为它们创建一个代码片段:可以通过键入特定的快捷短语来快速粘贴的一些代码。(它们在 VSCode、Atom 和 SublimeText 中称为片段,我假设其他编辑器也有类似的功能)
对于您假设的数学密集型应用程序(来自对问题的评论),您可以创建一个片段
import Vector from "path/to/Vector";
import Matrix from "path/to/Matrix";
import Tensor from "path/to/Tensor";
Run Code Online (Sandbox Code Playgroud)
创建新文件时快速导入所有这些内容。
你可以输入foo并按回车键,它会自动添加导入foo并按 Enter 键,它会自动在文件顶部我讨厌推销某个特定的编辑器,但如果您对导入的苦差事感到恼火,那么它确实非常有帮助。
如果您使用命名空间导入,也许只需选择一个较短的:u.foo仅比 稍长一点foo,但它比使用全局范围要简单得多。
| 归档时间: |
|
| 查看次数: |
392 次 |
| 最近记录: |