我将脚趾插入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);
}
答案 0 :(得分:3)
在TypeScript中,当您导入某些内容但仅将其用作类型时,TS会在编译代码时将其保留。在这种情况下,导入将消失,这意味着元素不会被注册,因此,当您尝试查询自定义元素时,方法就会丢失。之所以在这里对值进行类型检查是因为导入的类实际上被用作instanceof
的值,因此导入保持不变。
Here's an issue about it,以及一些解决方案。对于需要触发的副作用,请在入口JS文件顶部的import './engine/game.js'
确保其始终运行并注册该元素。