Rya*_*ugh 215 javascript module typescript
我有一些代码:
baseTypes.ts
export namespace Living.Things {
export class Animal {
move() { /* ... */ }
}
export class Plant {
photosynthesize() { /* ... */ }
}
}
Run Code Online (Sandbox Code Playgroud)
dog.ts
import b = require('./baseTypes');
export namespace Living.Things {
// Error, can't find name 'Animal', ??
export class Dog extends Animal {
woof() { }
}
}
Run Code Online (Sandbox Code Playgroud)
tree.ts
// Error, can't use the same name twice, ??
import b = require('./baseTypes');
import b = require('./dogs');
namespace Living.Things {
// Why do I have to write b.Living.Things.Plant instead of b.Plant??
class Tree extends b.Living.Things.Plant {
}
}
Run Code Online (Sandbox Code Playgroud)
这一切都非常令人困惑.我想让一堆外部模块为同一个命名空间贡献类型Living.Things.看来,这并不在所有的工作-我看不到Animal在dogs.ts.我要写完整的命名空间名称b.Living.Things.Plant在tree.ts.它不适用于跨文件在同一命名空间中组合多个对象.我该怎么做呢?
Rya*_*ugh 785
假设你写了一些像这样的代码:
Mod1.ts
export namespace A {
export class Twix { ... }
}
Run Code Online (Sandbox Code Playgroud)
Mod2.ts
export namespace A {
export class PeanutButterCup { ... }
}
Run Code Online (Sandbox Code Playgroud)
Mod3.ts
export namespace A {
export class KitKat { ... }
}
Run Code Online (Sandbox Code Playgroud)
每个模块(纸张)都有自己的杯子命名A.这没用 - 你实际上并没有在这里组织你的糖果,你只是在你和点心之间增加一个额外的步骤(从杯子里取出).
如果你没有使用模块,你可能会编写这样的代码(注意缺少export声明):
global1.ts
namespace A {
export class Twix { ... }
}
Run Code Online (Sandbox Code Playgroud)
global2.ts
namespace A {
export class PeanutButterCup { ... }
}
Run Code Online (Sandbox Code Playgroud)
global3.ts
namespace A {
export class KitKat { ... }
}
Run Code Online (Sandbox Code Playgroud)
此代码A在全局范围中创建合并的命名空间:
此设置很有用,但不适用于模块(因为模块不会污染全局范围).
让我们回到最初的例子,杯子A,A和A没有做你任何好处.相反,您可以将代码编写为:
Mod1.ts
export class Twix { ... }
Run Code Online (Sandbox Code Playgroud)
Mod2.ts
export class PeanutButterCup { ... }
Run Code Online (Sandbox Code Playgroud)
Mod3.ts
export class KitKat { ... }
Run Code Online (Sandbox Code Playgroud)
创建一个如下所示的图片:
好多了!
现在,如果你还在考虑你真的想在模块中使用命名空间,请继续阅读......
我们首先需要回到命名空间存在的起源,并检查这些原因是否对外部模块有意义.
组织:命名空间可以方便地将逻辑相关的对象和类型组合在一起.例如,在C#中,您将找到所有集合类型System.Collections.通过将我们的类型组织成分层命名空间,我们为这些类型的用户提供了良好的"发现"体验.
名称冲突:命名空间对于避免命名冲突很重要.例如,您可能拥有My.Application.Customer.AddForm和My.Application.Order.AddForm- 两个具有相同名称但具有不同名称空间的类型.在所有标识符都存在于同一根作用域中且所有程序集都加载所有类型的语言中,将所有内容都放在名称空间中至关重要.
这些原因在外部模块中有意义吗?
组织:外部模块必须已存在于文件系统中.我们必须通过路径和文件名来解决它们,因此我们有一个逻辑组织方案供我们使用.我们可以有一个/collections/generic/包含list模块的文件夹.
名称冲突:这在外部模块中根本不适用.在一个模块中,没有合理的理由让两个具有相同名称的对象.从消费方面来看,任何给定模块的消费者都会选择他们用来引用模块的名称,因此不可能发生意外命名冲突.
即使您不相信模块的工作原理能够充分解决这些原因,尝试在外部模块中使用命名空间的"解决方案"也无法工作.
一个故事:
你的朋友鲍勃打电话给你."我家里有一个很棒的新组织计划",他说,"来看看吧!".干得好,让我们看看Bob提出了什么.
你从厨房开始,打开食品室.有60个不同的盒子,每个盒子都标有"Pantry".你随机挑选一个盒子然后打开它.里面是一个标有"谷物"的盒子.打开"谷物"框,找到一个标有"Pasta"的方框.打开"Pasta"框,找到一个标有"Penne"的方框.你打开这个盒子,就像你期望的那样找到一袋通心粉.
有点困惑,你拿起一个相邻的盒子,也标有"Pantry".里面是一个盒子,再次标记为"谷物".打开"谷物"框,再次找到一个标有"Pasta"的方框.你打开"Pasta"框并找到一个盒子,这个盒子标有"Rigatoni".你打开这个盒子,找到一袋通心粉意大利面.
"这很棒!" 鲍勃说."一切都在命名空间!".
"但鲍勃......"你回答."你的组织方案是无用的.你必须打开一堆盒子才能找到任何东西,找到任何东西实际上并不比你把所有东西放在一个盒子而不是三个盒子里更方便.事实上,既然你的食品储藏室已经逐个分类,你根本不需要盒子.为什么不把面食放在架子上并在需要时拿起它?"
"你不明白 - 我需要确保没有其他人放置不属于'Pantry'命名空间的东西.而且我已经安全地将所有意大利面组织到
Pantry.Grains.Pasta命名空间中,这样我就可以轻松找到它"鲍勃是一个非常困惑的人.
你可能在现实生活中遇到了类似的事情:你在亚马逊上订购了一些东西,每件物品都出现在自己的盒子里,里面有一个小盒子,你的物品用自己的包装包装.即使内部箱子相似,货物也无法"合并".
与盒子类比,关键的观察是外部模块是他们自己的盒子.它可能是一个非常复杂的项目,具有许多功能,但任何给定的外部模块都是它自己的框.
现在我们已经发现我们不需要使用"名称空间",我们应该如何组织模块?一些指导原则和例子如下.
export default:MyClass.ts
export default class SomeType {
constructor() { ... }
}
Run Code Online (Sandbox Code Playgroud)
MyFunc.ts
function getThing() { return 'thing'; }
export default getThing;
Run Code Online (Sandbox Code Playgroud)
消费
import t from './MyClass';
import f from './MyFunc';
var x = new t();
console.log(f());
Run Code Online (Sandbox Code Playgroud)
这对消费者来说是最佳的.他们可以根据需要为您的类型命名(t在这种情况下),并且不必进行任何无关的点击来查找对象.
MyThings.ts
export class SomeType { ... }
export function someFunc() { ... }
Run Code Online (Sandbox Code Playgroud)
消费
import * as m from './MyThings';
var x = new m.SomeType();
var y = m.someFunc();
Run Code Online (Sandbox Code Playgroud)
module/ namespacekeyword:MyLargeModule.ts
export namespace Animals {
export class Dog { ... }
export class Cat { ... }
}
export namespace Plants {
export class Tree { ... }
}
Run Code Online (Sandbox Code Playgroud)
消费
import { Animals, Plants} from './MyLargeModule';
var x = new Animals.Dog();
Run Code Online (Sandbox Code Playgroud)
以下所有内容都是模块结构的红色标志.如果其中任何一个适用于您的文件,请仔细检查您是否尝试命名外部模块:
export module Foo { ... }(删除Foo所有内容并将其移动到某个级别)export class或export function不具有的文件export defaultexport module Foo {在顶级具有相同的多个文件(不要认为这些文件将组合成一个Foo!)Jef*_*pia 53
Ryan的答案没有错,但是对于那些来到这里寻找如何在仍然正确使用ES6命名空间的同时维护每个文件一个类文件结构的人来说,请参考Microsoft 提供的这个有用的资源.
在阅读文档后,我不清楚的一件事是:如何使用单个 导入整个(合并)模块import.
编辑 Circling返回以更新此答案.在TS中出现了一些命名空间的方法.
一个文件中的所有模块类.
export namespace Shapes {
export class Triangle {}
export class Square {}
}
Run Code Online (Sandbox Code Playgroud)
将文件导入命名空间,然后重新分配
import { Triangle as _Triangle } from './triangle';
import { Square as _Square } from './square';
export namespace Shapes {
export const Triangle = _Triangle;
export const Square = _Square;
}
Run Code Online (Sandbox Code Playgroud)
桶
// ./shapes/index.ts
export { Triangle } from './triangle';
export { Square } from './square';
// in importing file:
import * as Shapes from './shapes/index.ts';
// by node module convention, you can ignore '/index.ts':
import * as Shapes from './shapes';
let myTriangle = new Shapes.Triangle();
Run Code Online (Sandbox Code Playgroud)
最后的考虑.您可以命名每个文件
// triangle.ts
export namespace Shapes {
export class Triangle {}
}
// square.ts
export namespace Shapes {
export class Square {}
}
Run Code Online (Sandbox Code Playgroud)
但是,当从同一名称空间导入两个类时,TS会抱怨标识符重复.这次唯一的解决方案就是命名空间.
import { Shapes } from './square';
import { Shapes as _Shapes } from './triangle';
// ugh
let myTriangle = new _Shapes.Shapes.Triangle();
Run Code Online (Sandbox Code Playgroud)
这种混叠是绝对令人憎恶的,所以不要这样做.你最好采用上述方法.就个人而言,我更喜欢'桶'.
尝试按文件夹组织:
baseTypes.ts
export class Animal {
move() { /* ... */ }
}
export class Plant {
photosynthesize() { /* ... */ }
}
Run Code Online (Sandbox Code Playgroud)
dog.ts
import b = require('./baseTypes');
export class Dog extends b.Animal {
woof() { }
}
Run Code Online (Sandbox Code Playgroud)
tree.ts
import b = require('./baseTypes');
class Tree extends b.Plant {
}
Run Code Online (Sandbox Code Playgroud)
LivingThings.ts
import dog = require('./dog')
import tree = require('./tree')
export = {
dog: dog,
tree: tree
}
Run Code Online (Sandbox Code Playgroud)
main.ts
import LivingThings = require('./LivingThings');
console.log(LivingThings.Tree)
console.log(LivingThings.Dog)
Run Code Online (Sandbox Code Playgroud)
我们的想法是,您的模块本身不应该关心/知道它们正在参与命名空间,但这会以紧凑,合理的方式将您的API暴露给消费者,这与您为项目使用的模块系统类型无关.
小智 5
尝试这个命名空间模块
命名空间模块文件.ts
export namespace Bookname{
export class Snows{
name:any;
constructor(bookname){
console.log(bookname);
}
}
export class Adventure{
name:any;
constructor(bookname){
console.log(bookname);
}
}
}
export namespace TreeList{
export class MangoTree{
name:any;
constructor(treeName){
console.log(treeName);
}
}
export class GuvavaTree{
name:any;
constructor(treeName){
console.log(treeName);
}
}
}
Run Code Online (Sandbox Code Playgroud)
bookTreeCombine.ts
---编译部分---
import {Bookname , TreeList} from './namespaceModule';
import b = require('./namespaceModule');
let BooknameLists = new Bookname.Adventure('Pirate treasure');
BooknameLists = new Bookname.Snows('ways to write a book');
const TreeLis = new TreeList.MangoTree('trees present in nature');
const TreeLists = new TreeList.GuvavaTree('trees are the celebraties');
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
118481 次 |
| 最近记录: |