打字稿-在文件中执行代码而无需导入文件

时间:2018-07-25 01:52:36

标签: angular typescript

有什么方法可以在文件中运行代码而无需将它们导入TypeScript(Angular项目)中?也许通过在tsconfig中通过一些配置指定文件模式?

我想做的是将一些类注册到一个全局对象中,但是我不想在一个文件中维护类列表。我宁愿在每个类定义下使用简单的代码行,如下所示:

export class MyClassToRegister {...}

GlobalRegistry.register(MyClassToRegister);

我知道在导入文件时将执行此代码,但是有时为时已晚。关于如何实现这一目标?

2 个答案:

答案 0 :(得分:1)

一种解决方案是使用multi-file namespaces,该代码允许将代码拆分为多个文件,而不必导入modules

以下是TypeScript documentation on namespaces中的一个简化示例。

Validation.ts文件

namespace Validation {
    export interface StringValidator {
        isAcceptable(s: string): boolean;
    }
}

LettersOnlyValidator.ts文件

namespace Validation {
    const lettersRegexp = /^[A-Za-z]+$/;
    export class LettersOnlyValidator implements StringValidator {
        isAcceptable(s: string) {
            return lettersRegexp.test(s);
        }
    }
}

答案 1 :(得分:1)

是的,通过使用Webpack的require.context(...),您可以将文件目录导入到包中。

快速说明:您仍将文件导入捆绑包中,但是,如果添加/删除文件,则不必静态定义每个导入路径,也不必手动保持它们最新。

文件结构:

让我们使用以下示例文件结构:

src/
    items/
        item1.ts
        item2.ts
        item3.ts
    registry.ts
    index.ts

这是我们从目录中需要的项目:

//item1.ts, item2.ts, item3.ts
import GlobalRegistry from "../registry";

export class Item1 {
    //...
}
GlobalRegistry.register(Item1);

已加载的项目将在此服务(或您的任何业务逻辑)中注册自己-这证明已在加载项目:

//registry.ts
export default class GlobalRegistry {

    static _items = [];

    static register(cls){
        console.log('Register class: ', cls.name);
        this._items.push(cls.name);
    }

    static getItems(){
        return this._items;
    }

}

require.context(...)

使用require.context(...)要求'items'目录下的所有文件:

//index.ts
import GlobalRegistry from './registry';

// Import all files under './items/*.ts'
var context = require.context('./items', true, /\.ts$/);
context.keys().forEach((key) => {
    context(key);
});

console.log('Loaded classes:', GlobalRegistry.getItems());

最后,为了让TypeScript满意,我们声明了Webpack提供的require.context()接口:

//references.d.ts

// Extend @types/node NodeRequire type to define Webpack's context function
declare interface NodeRequire {
    context: (dir: string, includeSubdirs: boolean, filter: RegExp) => any;
}

// Tell TypeScript that there is a global `require` variable available to us
declare var require: NodeRequire;

结果:

应用程序运行时,您应该会看到以下信息:

Register class:  Item1
Register class:  Item2
Register class:  Item3
Loaded classes: (3) ["Item1", "Item2", "Item3"]

注意:

1。包含顺序 如果您先引用单个类,则不能保证包含的顺序。

例如,如果您明确导入类型并将其用作值,则该类型将在仅通过require.context(...)包含的其他类型之前加载。

示例-使用Item2作为值:

//index.ts

/* require.context(...) stuff is here */

import {Item2} from './items/Item2';
let myItem = new Item2();   // use Item2 as a value

更改加载顺序:

Register class:  Item2
Register class:  Item1
Register class:  Item3
Loaded classes: (3) ["Item2", "Item1", "Item3"]

但是请注意,仅按类型(而不是按值)引用不会更改加载顺序

let myItem: Item2;  // just referencing by type won't affect load order

2。需要功能依赖项警告

在构建期间,您可能会收到警告,例如:require function is used in a way in which dependencies cannot be statically extracted

不一定有什么错误,只是Webpack会让您知道您正在使用require做一些时髦的事情-这是真的:)

执行此动态要求可能会影响捆绑软件的摇树或其他静态分析(即,如果不使用这些类型,则不能从捆绑软件中排除这些类型)。但这不必手动管理文件导入,这可能是一个公平的取舍-您必须根据自己的需求/项目目标进行评估。