【问题标题】:Typescript module factory patternTypescript 模块工厂模式
【发布时间】:2016-11-01 08:29:44
【问题描述】:

node.js 中有一种众所周知的方法来利用模块工厂模式。例如:

m.js

function factoryMethod(module) {
  // doing some stuff and returning object initialized with module parameter
}

app.js

var o = require('./m')(module);
// using o

我怎样才能在打字稿中做同样的事情。其实创建 m.ts 是没有问题的:

m.ts

function factoryMethod(module: NodeModule): any {
  // doing some stuff
}

export = factoryMethod;

但是我应该如何使用导入语法来使用这个模块工厂方法,就像在 javascript 中一样?

【问题讨论】:

    标签: javascript node.js typescript


    【解决方案1】:

    我不确定我是否完全理解这种常见模式。您将module 对象从一个模块传递到另一个模块?各种其他对象都是这样传递的(例如appdb),但我不喜欢传递module 对象的想法。我很想将其称为反模式。当然module 对象应该保留在它所属的模块中。

    也就是说,如果您只想在同一行导入和调用一个函数,您可以使用 Node 的 require() 函数来执行此操作,就像常规 JavaScript 一样。假设您传递的是 Express app 而不是 module

    const o = require('./m')(app);
    

    但是,您会因此而失去类型安全性; o 将是 any 类型。您必须明确定义 o 的类型。

    const o: Module = require('./m')(app);
    

    这有点傻。事实上,Module 无论如何都可能在您需要的模块中定义,因此它也很可能弄巧成拙。我的建议是这样的。不要期望在 TypeScript 中使用与普通 JS 相同的模式,TypeScript 有自己的模式。

    您可以做的一件事是在顶部导入函数,然后稍后调用它。 TypeScript 使用ES2015-style modules,它不允许您导入函数并在同一行调用它。您将不得不重写这两个文件,因为 export = 在 ES2015 中无效。

    // m.ts
    
    interface Module {
      // properties, methods, etc.
    }
    
    export function factoryMethod(app: Express.Application): Module {
      let module = {};
      // Initialize module methods, properties, etc.
      return module;
    }
    

    接口允许app.ts中的类型推断,是一种改进。

    // app.ts
    
    import {factoryMethod} from './m';
    
    // ...
    
    let o = factoryMethod(app);
    

    但这仍然很愚蠢。我们不需要定义接口和所有那些废话。相反,我们可以使用 class。类通常是 TypeScript 中的答案,您会发现 TypeScript 中的大多数模式都涉及到它们。

    // m.ts
    
    export class Module {
    
      constructor(private app: Express.Application) { }
    
      cache: string[];
    
      someMethod(): Promise<Express.Response> {
        // do something with this.app
      }
    
    }
    

    然后在app.ts

    import {Module} from './m';
    
    // ...
    
    let o = new Module(app);
    

    现在我们不必担心接口和所有这些。类本身就是一种类型。这与您在典型 Node 应用程序中可能看到的有很大不同,但它是您在 TypeScript 中经常发现的那种模式。

    希望能给你一些想法。

    【讨论】:

    • 感谢您的回答。使用模块作为参数就像一个例子。共同的想法是拥有某种工厂模式,并不强制使用模块。好的,无论如何,谢谢。
    • @AndreiTarutin 好的,我认为有一些我完全不知道的奇怪模式。我很高兴能帮上忙。
    【解决方案2】:
    import {factoryMethod} from './m.ts'
    
    
    let module = factpryMethod('module');
    

    【讨论】:

    • 其实我的意思是像在javascript中那样,导入加初始化一行。
    【解决方案3】:

    我知道这个问题已经相当老了,但是在将现有的 JS 项目转换为使用这种模式的 TypeScript 时,我遇到了同样的问题。

    我们可以使用ReturnType helper 来获取函数返回类型的类型定义,而不是必须在接口中预先定义模块定义!

    这可能是模块的样子:

    function initModule(arg1: number, arg2: number) {
      function functionA() {
        return arg1;
      }
      function functionB() {
        return arg2;
      }
    
      return {
        functionA,
        functionB,
      };
    }
    
    export default initModule;
    
    export type SampleModule = ReturnType<typeof initFactory>;
    
    

    我们可以这样使用它:

    import initModule, { SampleModule } from './factory';
    
    const newModule: SampleModule = initModule(1, 2);
    
    newModule.functionA(); // 1
    newModule.functionB(); // 2
    

    说真的,TypeScript 有多酷? :)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-07-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-25
      相关资源
      最近更新 更多