TypeScript跨文件调用Map时get()返回undefined问题求助
问题根源与解决方案
1. Map未初始化导致的隐性异常
你的SpriteSet类中map属性仅做了类型声明,但未在构造函数中显式初始化。虽然JavaScript会自动将未赋值的属性设为undefined,但后续调用this.map.set()时浏览器会隐式创建Map实例——这种隐式创建会引发引用一致性问题,叠加异步加载的时序问题后,就出现了控制台显示有数据但实际访问不到的诡异现象。
修复方法:在SpriteSet构造函数中显式初始化Map:
export class SpriteSet { map: Map<string, Sprite>; constructor() { this.map = new Map<string, Sprite>(); // 显式初始化Map实例 } // ... 其他代码 }
2. 异步加载的时序错误
addToSpriteSet中的img.onload是异步回调,调用addToSpriteSet后代码会继续执行,而Map的填充操作要等到图片加载完成后才会触发。当你调用MapBuilder.load()时,大概率图片还未加载完成,此时map实际是空的(size为0,get()返回undefined)。
浏览器控制台显示Map有数据,是因为控制台会保留对象引用,后续异步操作填充Map后,控制台会更新显示,但此时你的代码已经执行过get()逻辑了。
修复方法:将addToSpriteSet改为返回Promise,确保图片加载完成后再执行load():
export class SpriteSet { map: Map<string, Sprite>; constructor() { this.map = new Map<string, Sprite>(); } addToSpriteSet(path: string, arr: string[]): Promise<void> { return new Promise((resolve) => { const img = new Image(); img.src = path; img.onload = () => { const spriteCountX = img.width / 16; for (let i = 0; i < img.height / 16; i++) { for (let j = 0; j < spriteCountX; j++) { const spr = new Sprite(img.src, j * 16, i * 16); const keyIndex = i * spriteCountX + j; this.map.set(arr[keyIndex], spr); } } resolve(); // 加载完成后通知外部 }; // 可选:处理图片加载失败场景 img.onerror = () => { console.error(`加载图片失败: ${path}`); resolve(); }; }); } }
调用时需等待addToSpriteSet完成后再执行load():
// 示例初始化逻辑 async function init() { const spriteSet = new SpriteSet(); await spriteSet.addToSpriteSet("path/to/your/sprite.png", ["grass", ...其他键名]); const mapBuilder = new MapBuilder(); mapBuilder.sprites = spriteSet; // 初始化tiles、code等其他属性... mapBuilder.load(); } init();
额外优化点
- 修复上述问题后,无需再使用
Map.prototype.get.call这种怪异写法,直接用this.sprites.map.get(key)即可正常访问。 - 给
MapBuilder添加background属性的类型声明,当前代码中setBackground方法操作的this.background未在类中声明,会触发TypeScript报错。
内容的提问来源于stack exchange,提问作者Ian G.
相关产品推荐
相关产品推荐

