From 51b3e42f4dd3aa879986e67595302d9168b9c847 Mon Sep 17 00:00:00 2001 From: Erik Onarheim Date: Mon, 5 Aug 2024 10:27:48 -0500 Subject: [PATCH] fix: [#3167] Increase strictness in Resource types (#3168) Closes #3167 --- CHANGELOG.md | 6 ++- src/engine/Resources/Gif.ts | 63 ++++++++++++---------- src/engine/Resources/Sound/AudioContext.ts | 4 +- src/engine/Resources/Sound/Sound.ts | 10 ++-- src/engine/Resources/tsconfig.json | 6 +++ src/engine/TileMap/TileMap.ts | 8 ++- 6 files changed, 58 insertions(+), 39 deletions(-) create mode 100644 src/engine/Resources/tsconfig.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 079ee9307..dd2143c07 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -122,8 +122,10 @@ are doing mtv adjustments during precollision. ### Changed -- Applied increased TS strictness for the Graphics API subtree -- Applied increased TS strictness for the TileMap API subtree +- Applied increased TS strictness: + * Resource API subtree + * Graphics API subtree + * TileMap API subtree diff --git a/src/engine/Resources/Gif.ts b/src/engine/Resources/Gif.ts index 775dece38..0e8ffe44a 100644 --- a/src/engine/Resources/Gif.ts +++ b/src/engine/Resources/Gif.ts @@ -17,20 +17,20 @@ export class Gif implements Loadable { /** * The width of the texture in pixels */ - public width: number; + public width: number = 0; /** * The height of the texture in pixels */ - public height: number; + public height: number = 0; - private _stream: Stream = null; - private _gif: ParseGif = null; + private _stream?: Stream; + private _gif?: ParseGif; private _textures: ImageSource[] = []; - private _animation: Animation = null; - private _transparentColor: Color = null; + private _animation?: Animation; + private _transparentColor: Color; - public data: ImageSource[]; + public data: ImageSource[] = []; /** * @param path Path to the image resource @@ -80,33 +80,40 @@ export class Gif implements Loadable { * Return a frame of the gif as a sprite by id * @param id */ - public toSprite(id: number = 0): Sprite { - const sprite = this._textures[id].toSprite(); - return sprite; + public toSprite(id: number = 0): Sprite | null { + const sprite = this._textures[id]?.toSprite(); + return sprite ?? null; } /** * Return the gif as a spritesheet */ - public toSpriteSheet(): SpriteSheet { + public toSpriteSheet(): SpriteSheet | null { const sprites: Sprite[] = this._textures.map((image) => { return image.toSprite(); }); - return new SpriteSheet({ sprites }); + if (sprites.length) { + return new SpriteSheet({ sprites }); + } + + return null; } /** * Transform the GIF into an animation with duration per frame */ - public toAnimation(durationPerFrameMs: number): Animation { - const spriteSheet: SpriteSheet = this.toSpriteSheet(); - const length = spriteSheet.sprites.length; - this._animation = Animation.fromSpriteSheet(spriteSheet, range(0, length), durationPerFrameMs); - return this._animation; + public toAnimation(durationPerFrameMs: number): Animation | null { + const spriteSheet = this.toSpriteSheet(); + const length = spriteSheet?.sprites.length; + if (length) { + this._animation = Animation.fromSpriteSheet(spriteSheet, range(0, length), durationPerFrameMs); + return this._animation; + } + return null; } public get readCheckBytes(): number[] { - return this._gif.checkBytes; + return this._gif?.checkBytes ?? []; } } @@ -217,8 +224,8 @@ const lzwDecode = function (minCodeSize: number, data: any) { dict[eoiCode] = null; }; - let code; - let last; + let code = 0; + let last = 0; while (true) { last = code; @@ -256,9 +263,9 @@ const lzwDecode = function (minCodeSize: number, data: any) { // The actual parsing; returns an object with properties. export class ParseGif { - private _st: Stream = null; + private _st: Stream; private _handler: any = {}; - private _transparentColor: Color = null; + private _transparentColor: Color; public frames: GifFrame[] = []; public images: HTMLImageElement[] = []; public globalColorTable: any[] = []; @@ -445,15 +452,15 @@ export class ParseGif { }; parseImg = (img: any) => { - const deinterlace = (pixels: any, width: any) => { + const deinterlace = (pixels: any, width: number) => { // Of course this defeats the purpose of interlacing. And it's *probably* // the least efficient way it's ever been implemented. But nevertheless... - const newPixels = new Array(pixels.length); + const newPixels: number[] = new Array(pixels.length); const rows = pixels.length / width; - const cpRow = (toRow: any, fromRow: any) => { + const cpRow = (toRow: number, fromRow: number) => { const fromPixels = pixels.slice(fromRow * width, (fromRow + 1) * width); - newPixels.splice.apply(newPixels, [toRow * width, width].concat(fromPixels)); + newPixels.splice.apply(newPixels, [toRow * width, width].concat(fromPixels) as any); }; const offsets = [0, 4, 2, 1]; @@ -536,12 +543,12 @@ export class ParseGif { arrayToImage = (frame: GifFrame) => { let count = 0; - const c = document.createElement('canvas'); + const c = document.createElement('canvas')!; c.id = count.toString(); c.width = frame.width; c.height = frame.height; count++; - const context = c.getContext('2d'); + const context = c.getContext('2d')!; const pixSize = 1; let y = 0; let x = 0; diff --git a/src/engine/Resources/Sound/AudioContext.ts b/src/engine/Resources/Sound/AudioContext.ts index db11d0b52..faac91bb3 100644 --- a/src/engine/Resources/Sound/AudioContext.ts +++ b/src/engine/Resources/Sound/AudioContext.ts @@ -3,7 +3,7 @@ */ /* istanbul ignore next */ export class AudioContextFactory { - private static _INSTANCE: AudioContext = null; + private static _INSTANCE?: AudioContext; public static create(): AudioContext { if (!this._INSTANCE) { @@ -12,6 +12,6 @@ export class AudioContextFactory { } } - return this._INSTANCE; + return this._INSTANCE!; } } diff --git a/src/engine/Resources/Sound/Sound.ts b/src/engine/Resources/Sound/Sound.ts index 4fcebb0b3..84281a188 100644 --- a/src/engine/Resources/Sound/Sound.ts +++ b/src/engine/Resources/Sound/Sound.ts @@ -38,7 +38,7 @@ export const SoundEvents = { export class Sound implements Audio, Loadable { public events = new EventEmitter(); public logger: Logger = Logger.getInstance(); - public data: AudioBuffer; + public data!: AudioBuffer; private _resource: Resource; /** * Indicates whether the clip should loop when complete @@ -122,7 +122,7 @@ export class Sound implements Audio, Loadable { private _isStopped = false; // private _isPaused = false; private _tracks: Audio[] = []; - private _engine: Engine; + private _engine?: Engine; private _wasPlayingOnHidden: boolean = false; private _playbackRate = 1.0; private _audioContext = AudioContextFactory.create(); @@ -340,7 +340,7 @@ export class Sound implements Audio, Loadable { } private async _resumePlayback(): Promise { - if (this.isPaused) { + if (this.isPaused()) { const resumed: Promise[] = []; // ensure we resume *current* tracks (if paused) for (const track of this._tracks) { @@ -388,7 +388,7 @@ export class Sound implements Audio, Loadable { newTrack.loop = this.loop; newTrack.volume = this.volume; - newTrack.duration = this.duration; + newTrack.duration = this.duration ?? 0; newTrack.playbackRate = this._playbackRate; this._tracks.push(newTrack); @@ -418,6 +418,6 @@ export class Sound implements Audio, Loadable { public off(eventName: string, handler: Handler): void; public off(eventName: string): void; public off | string>(eventName: TEventName, handler?: Handler): void { - this.events.off(eventName, handler); + this.events.off(eventName, handler as any); } } diff --git a/src/engine/Resources/tsconfig.json b/src/engine/Resources/tsconfig.json new file mode 100644 index 000000000..20d5e2e03 --- /dev/null +++ b/src/engine/Resources/tsconfig.json @@ -0,0 +1,6 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "strict": true + } +} diff --git a/src/engine/TileMap/TileMap.ts b/src/engine/TileMap/TileMap.ts index 667ce4355..ca1f7700c 100644 --- a/src/engine/TileMap/TileMap.ts +++ b/src/engine/TileMap/TileMap.ts @@ -458,13 +458,17 @@ export class TileMap extends Entity { /** * Returns the {@apilink Tile} by index (row major order) + * + * Returns null if out of bounds */ - public getTileByIndex(index: number): Tile { - return this.tiles[index]; + public getTileByIndex(index: number): Tile | null { + return this.tiles[index] ?? null; } /** * Returns the {@apilink Tile} by its x and y integer coordinates * + * Returns null if out of bounds + * * For example, if I want the tile in fifth column (x), and second row (y): * `getTile(4, 1)` 0 based, so 0 is the first in row/column */