JavaScript和Typescript中模块导入之间的区别?

迈克尔

我将脚趾插入Shadow DOM / Custom元素,并认为我发现JS和TS如何处理模块化导入之间存在古怪之处,或者我做错了什么?

我的主要JS文件看起来像这样...

// import classes (and register custom elements)
import { Game } from './engine/game.js';
import { MainMenuState } from './menu/main-menu-state.js';

// get the game custom element from the DOM and create the main menu state
const oGame = document.querySelector('test-game');
const oState = document.createElement('main-menu-state');

// push the state onto the game
oGame.setState(oState);

模块看起来像这样...

export class Game extends HTMLElement {

    constructor() {
        super();
        this._shadowRoot = this.attachShadow({
            mode: 'open'
        });
    }

    setState(oState) { ... }

    pushState(oState) { ... }

    popState() { ... }

}

if(!customElements.get('test-game')) {
    customElements.define('test-game', Game);
}

正如您在模块底部看到的那样,我正在使用Game类定义自定义的test-game元素。主菜单状态元件被以类似的方式定义。

这工作正常,代码按预期执行

将这段代码转换为Typescript后,我遇到了问题。

TS的主要档案看起来像这样...

import { StateInterface } from './engine/state.interface.js';

import { Game } from './engine/game.js';
import { MainMenuState } from './menu/main-menu-state.js';

const oGame: Game = document.querySelector('test-game') as Game;
const oState: StateInterface = document.createElement('main-menu-state') as MainMenuState;

oGame.setState(oState);

TS模块看起来很熟悉...

export class Game extends HTMLElement implements GameInterface {

    public constructor() {
        super();

        this._shadowRoot = this.attachShadow({
            mode: 'open'
        });
    }

    public setState(oState: StateInterface): void { ... }

    public pushState(oState: StateInterface): void { ... }

    public popState(): void { ... }

}

if(!customElements.get('test-game')) {
    customElements.define('test-game', Game);
}

但是这次浏览器控制台给我以下错误...

未捕获的TypeError:oGame.setState在main.ts:9处不是函数

我的tsconfig文件设置为使用ES6模块分辨率...

{
    "compilerOptions": {
        "module": "es6",
        "target": "es6",
        "noImplicitAny": true,
        "removeComments": true,
        "preserveConstEnums": true,
        "sourceMap": true,
        "alwaysStrict": true,
        "noUnusedLocals": true,
        "outDir": "./public/js",
        "rootDir": "./public/ts"
    }
}

我只是不明白为什么这两段代码之间会有区别,除非TS编译器对模块导出做了不同的事情


编辑

好的,看来这是TS编译器引起的时髦现象。只需对对象进行类型检查就可以理顺...

import { StateInterface } from './engine/state.interface.js';

import { Game } from './engine/game.js';
import { MainMenuState } from './menu/main-menu-state.js';

const oGame: Game = document.querySelector('test-game') as Game;
const oState: StateInterface = document.createElement('main-menu-state') as MainMenuState;

if(oGame instanceof Game && oState instanceof MainMenuState) {
    oGame.setState(oState);
}
金达罗

在TypeScript中,当您导入某些内容但仅将其用作类型时,TS会在编译代码时将其保留。在这种情况下,导入将消失,这意味着元素未注册,因此,当您尝试查询自定义元素时,方法就会丢失。之所以在此处对值进行类型检查是因为导入的类实际上被用作的值instanceof,因此保留导入。

这是一个问题,其中也包含一些解决方案。对于需要触发的副作用,请import './engine/game.js'在条目JS文件的顶部确保它始终运行并注册该元素。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章