gpt4 book ai didi

javascript - 如何在 TypeScript 外部模块中使用命名空间?

转载 作者:行者123 更新时间:2023-12-01 17:54:08 24 4
gpt4 key购买 nike

我有一些代码:

baseTypes.ts

export namespace Living.Things {
export class Animal {
move() { /* ... */ }
}
export class Plant {
photosynthesize() { /* ... */ }
}
}

dog.ts
import b = require('./baseTypes');

export namespace Living.Things {
// Error, can't find name 'Animal', ??
export class Dog extends Animal {
woof() { }
}
}

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 {

}
}

这一切都非常令人困惑。我想让一堆外部模块都为同一个命名空间贡献类型, Living.Things .看来这根本行不通——我看不到 Animaldogs.ts .我必须写出完整的命名空间名称 b.Living.Things.Planttree.ts .跨文件组契约(Contract)一命名空间中的多个对象是行不通的。我该怎么做呢?

最佳答案

糖果杯比喻
版本 1:每个糖果一个杯子
假设你写了一些这样的代码:
Mod1.ts

export namespace A {
export class Twix { ... }
}
Mod2.ts
export namespace A {
export class PeanutButterCup { ... }
}
Mod3.ts
export namespace A {
export class KitKat { ... }
}
您已创建此设置:
enter image description here
每个模块(一张纸)都有自己的杯子,名为 A .这是没用的 - 你实际上并没有在这里整理你的糖果,你只是在你和零食之间增加了一个额外的步骤(把它从杯子里拿出来)。

版本 2:全局范围内的一杯
如果你没有使用模块,你可能会写这样的代码(注意缺少 export 声明):
global1.ts
namespace A {
export class Twix { ... }
}
global2.ts
namespace A {
export class PeanutButterCup { ... }
}
global3.ts
namespace A {
export class KitKat { ... }
}
这段代码创建了一个合并的命名空间 A在全局范围内:
enter image description here
此设置很有用,但不适用于模块的情况(因为模块不会污染全局范围)。

版本 3:无杯
回到最初的例子,杯子 A , A , 和 A对你没有任何好处。相反,您可以将代码编写为:
Mod1.ts
export class Twix { ... }
Mod2.ts
export class PeanutButterCup { ... }
Mod3.ts
export class KitKat { ... }
创建一个看起来像这样的图片:
enter image description here
好多了!
现在,如果你还在考虑你真正想要在你的模块中使用命名空间的程度,请继续阅读......

这些不是您要寻找的概念
我们首先需要回到命名空间存在的起源,并检查这些原因是否对外部模块有意义。
组织:命名空间可方便地将逻辑相关的对象和类型组合在一起。例如,在 C# 中,您将在 System.Collections 中找到所有集合类型。 .通过将我们的类型组织到分层命名空间中,我们为这些类型的用户提供了良好的“发现”体验。
名称冲突:命名空间对于避免命名冲突很重要。例如,您可能有 My.Application.Customer.AddFormMy.Application.Order.AddForm -- 名称相同但命名空间不同的两种类型。在所有标识符都存在于同一个根作用域中并且所有程序集加载所有类型的语言中,将所有内容都放在一个命名空间中是至关重要的。
这些原因在外部模块中有意义吗?
组织:外部模块必然已经存在于文件系统中。我们必须通过路径和文件名来解析它们,因此我们可以使用一个逻辑组织方案。我们可以有一个 /collections/generic/带有 list 的文件夹其中的模块。
名称冲突:这根本不适用于外部模块。在一个模块中,没有合理的理由有两个同名的对象。从消费方面来看,任何给定模块的消费者都可以选择他们将用来引用模块的名称,因此不可能发生意外的命名冲突。

即使您不相信模块的工作方式可以充分解决这些原因,尝试在外部模块中使用命名空间的“解决方案”甚至不起作用。
盒中盒盒中盒
一个故事:

Your friend Bob calls you up. "I have a great new organization scheme in my house", he says, "come check it out!". Neat, let's go see what Bob has come up with.

You start in the kitchen and open up the pantry. There are 60 different boxes, each labelled "Pantry". You pick a box at random and open it. Inside is a single box labelled "Grains". You open up the "Grains" box and find a single box labelled "Pasta". You open the "Pasta" box and find a single box labelled "Penne". You open this box and find, as you expect, a bag of penne pasta.

Slightly confused, you pick up an adjacent box, also labelled "Pantry". Inside is a single box, again labelled "Grains". You open up the "Grains" box and, again, find a single box labelled "Pasta". You open the "Pasta" box and find a single box, this one is labelled "Rigatoni". You open this box and find... a bag of rigatoni pasta.

"It's great!" says Bob. "Everything is in a namespace!".

"But Bob..." you reply. "Your organization scheme is useless. You have to open up a bunch of boxes to get to anything, and it's not actually any more convenient to find anything than if you had just put everything in one box instead of three. In fact, since your pantry is already sorted shelf-by-shelf, you don't need the boxes at all. Why not just set the pasta on the shelf and pick it up when you need it?"

"You don't understand -- I need to make sure that no one else puts something that doesn't belong in the 'Pantry' namespace. And I've safely organized all my pasta into the Pantry.Grains.Pasta namespace so I can easily find it"

Bob is a very confused man.


模块是他们自己的盒子
你可能在现实生活中遇到过类似的事情:你在亚马逊上订购了一些东西,每件商品都出现在自己的盒子里,里面有一个较小的盒子,你的物品用自己的包装包裹。即使内部盒子相似, cargo 也不会有效地“组合”。
与盒子类比,关键观察是外部模块是它们自己的盒子。它可能是一个具有很多功能的非常复杂的项目,但任何给定的外部模块都是它自己的盒子。

外部模块指南
既然我们已经发现我们不需要使用“命名空间”,那么我们应该如何组织我们的模块呢?以下是一些指导原则和示例。
尽可能接近顶级导出
  • 如果您只导出单个类或函数,请使用 export default :

  • MyClass.ts
    export default class SomeType {
    constructor() { ... }
    }
    MyFunc.ts
    function getThing() { return 'thing'; }
    export default getThing;
    消费
    import t from './MyClass';
    import f from './MyFunc';
    var x = new t();
    console.log(f());
    这对消费者来说是最佳的。他们可以随意命名您的类型(在本例中为 t),并且无需进行任何无关的打点即可找到您的对象。
  • 如果您要导出多个对象,请将它们全部放在顶级:

  • MyThings.ts
    export class SomeType { ... }
    export function someFunc() { ... }
    消费
    import * as m from './MyThings';
    var x = new m.SomeType();
    var y = m.someFunc();
  • 如果您要导出大量内容,那么您才应该使用 module/namespace关键词:

  • MyLargeModule.ts
    export namespace Animals {
    export class Dog { ... }
    export class Cat { ... }
    }
    export namespace Plants {
    export class Tree { ... }
    }
    消费
    import { Animals, Plants} from './MyLargeModule';
    var x = new Animals.Dog();

    红旗
    以下所有内容都是模块结构的危险信号。如果其中任何一个适用于您的文件,请仔细检查您是否没有尝试命名外部模块:
  • 唯一顶级声明为 export module Foo { ... } 的文件(删除 Foo 并将所有内容“上移”一个级别)
  • 具有单个 export class 的文件或 export function那不是 export default
  • 具有相同 export module Foo { 的多个文件在顶层(不要认为这些会合并成一个 Foo !)
  • 关于javascript - 如何在 TypeScript 外部模块中使用命名空间?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30357634/

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