diff --git a/package.json b/package.json index 1b1437e1e4..f95165db06 100644 --- a/package.json +++ b/package.json @@ -66,7 +66,7 @@ "semver": "^7.3.4", "shell-env": "^3.0.1", "tmp": "0.2.1", - "tslib": "^2.1.0", + "tslib": "^2.6.0", "update-electron-app": "^2.0.1" }, "devDependencies": { @@ -117,7 +117,7 @@ "eslint-plugin-prettier": "^3.3.1", "eslint-plugin-react": "^7.22.0", "fetch-mock-jest": "^1.5.1", - "fork-ts-checker-webpack-plugin": "^7.2.11", + "fork-ts-checker-webpack-plugin": "^8.0.0", "husky": "^5.1.1", "jest": "^29.5.0", "jest-environment-jsdom": "^29.5.0", @@ -141,8 +141,8 @@ "stylelint-config-standard": "^34.0.0", "terser-webpack-plugin": "^5.3.3", "ts-jest": "^29.1.1", - "ts-loader": "^9.3.1", - "typescript": "~4.3.0", + "ts-loader": "^9.4.4", + "typescript": "^5.1.6", "webpack": "^5.69.1" }, "lint-staged": { diff --git a/src/main/windows.ts b/src/main/windows.ts index 2db3722eb2..29196f10c1 100644 --- a/src/main/windows.ts +++ b/src/main/windows.ts @@ -101,7 +101,6 @@ export function createMainWindow(): Electron.BrowserWindow { }); ipcMainManager.handle(IpcEvents.GET_APP_PATHS, () => { - const paths = {}; const pathsToQuery = [ 'home', 'appData', @@ -110,6 +109,7 @@ export function createMainWindow(): Electron.BrowserWindow { 'downloads', 'desktop', ] as const; + const paths = {} as Record; for (const path of pathsToQuery) { paths[path] = app.getPath(path); } diff --git a/src/renderer/app.tsx b/src/renderer/app.tsx index 786ffbf944..e7a61f61b5 100644 --- a/src/renderer/app.tsx +++ b/src/renderer/app.tsx @@ -2,7 +2,12 @@ import * as path from 'node:path'; import { autorun, reaction, when } from 'mobx'; -import { EditorValues, PACKAGE_NAME, SetFiddleOptions } from '../interfaces'; +import { + EditorId, + EditorValues, + PACKAGE_NAME, + SetFiddleOptions, +} from '../interfaces'; import { defaultDark, defaultLight } from '../themes-defaults'; import { USER_DATA_PATH } from './constants'; import { ElectronTypes } from './electron-types'; @@ -92,7 +97,10 @@ export class App { const values = this.state.editorMosaic.values(); if (options) { - values[PACKAGE_NAME] = await getPackageJson(this.state, options); + values[PACKAGE_NAME as EditorId] = await getPackageJson( + this.state, + options, + ); } return values; diff --git a/src/renderer/components/commands-action-button.tsx b/src/renderer/components/commands-action-button.tsx index bd7faeff5f..91db78fca0 100644 --- a/src/renderer/components/commands-action-button.tsx +++ b/src/renderer/components/commands-action-button.tsx @@ -14,9 +14,11 @@ import { when } from 'mobx'; import { observer } from 'mobx-react'; import { + EditorId, EditorValues, GistActionState, GistActionType, + PACKAGE_NAME, } from '../../interfaces'; import { AppState } from '../state'; import { ensureRequiredFiles } from '../utils/editor-utils'; @@ -125,7 +127,8 @@ export const GistActionButton = observer( options, ); - defaultGistValues['package.json'] = currentEditorValues['package.json']; + defaultGistValues[PACKAGE_NAME as EditorId] = + currentEditorValues[PACKAGE_NAME as EditorId]; try { const gistFilesList = appState.isPublishingGistAsRevision diff --git a/src/renderer/components/output-editors-wrapper.tsx b/src/renderer/components/output-editors-wrapper.tsx index 12914c4199..7dc0ad1182 100644 --- a/src/renderer/components/output-editors-wrapper.tsx +++ b/src/renderer/components/output-editors-wrapper.tsx @@ -54,7 +54,9 @@ export class OutputEditorsWrapper extends React.Component< public render() { return ( - renderTile={(id: string) => this.MOSAIC_ELEMENTS[id]} + renderTile={(id: string) => + this.MOSAIC_ELEMENTS[id as keyof typeof this.MOSAIC_ELEMENTS] + } resize={{ minimumPaneSizePercentage: 15 }} value={this.state.mosaic} onChange={this.onChange} diff --git a/src/renderer/components/settings-execution.tsx b/src/renderer/components/settings-execution.tsx index 4f1cf068b7..7b967ba1ec 100644 --- a/src/renderer/components/settings-execution.tsx +++ b/src/renderer/components/settings-execution.tsx @@ -15,13 +15,10 @@ import { observer } from 'mobx-react'; import { GlobalSetting, IPackageManager } from '../../interfaces'; import { AppState } from '../state'; -/** - * @TODO make this a proper enum again once we update Typescript - */ -export const SettingItemType = { - EnvVars: GlobalSetting.environmentVariables, - Flags: GlobalSetting.executionFlags, -} as const; +export enum SettingItemType { + EnvVars = GlobalSetting.environmentVariables, + Flags = GlobalSetting.executionFlags, +} interface ExecutionSettingsProps { appState: AppState; @@ -118,11 +115,11 @@ export const ExecutionSettings = observer( * run with the Electron executable. * * @param {React.ChangeEvent} event - * @param {GlobalSetting} type + * @param {SettingItemType} type */ public handleSettingsItemChange( event: React.ChangeEvent, - type: GlobalSetting, + type: SettingItemType, ) { const { name, value } = event.currentTarget; @@ -137,9 +134,9 @@ export const ExecutionSettings = observer( /** * Adds a new settings item input field. * - * @param {GlobalSetting} type + * @param {SettingItemType} type */ - private addNewSettingsItem(type: GlobalSetting) { + private addNewSettingsItem(type: SettingItemType) { const array = Object.entries(this.state[type]); this.setState((prevState) => ({ @@ -163,7 +160,7 @@ export const ExecutionSettings = observer( appState.packageManager = value as IPackageManager; }; - public renderDeleteItem(idx: string, type: GlobalSetting): JSX.Element { + public renderDeleteItem(idx: string, type: SettingItemType): JSX.Element { const updated = this.state[type]; const removeFn = () => { diff --git a/src/renderer/components/sidebar.tsx b/src/renderer/components/sidebar.tsx index 9f434da103..0b94bdbf34 100644 --- a/src/renderer/components/sidebar.tsx +++ b/src/renderer/components/sidebar.tsx @@ -13,7 +13,7 @@ export const Sidebar = ({ appState }: { appState: AppState }) => { }; return ( - renderTile={(id) => ELEMENT_MAP[id]} + renderTile={(id) => ELEMENT_MAP[id as keyof typeof ELEMENT_MAP]} initialValue={{ first: 'fileTree', second: 'packageManager', diff --git a/src/renderer/file-manager.ts b/src/renderer/file-manager.ts index 7eac025a55..8529fd913c 100644 --- a/src/renderer/file-manager.ts +++ b/src/renderer/file-manager.ts @@ -4,6 +4,8 @@ import * as fs from 'fs-extra'; import semver from 'semver'; import { + EditorId, + EditorValues, FileTransform, Files, GenericDialogType, @@ -70,7 +72,7 @@ export class FileManager { console.log(`FileManager: Asked to open`, filePath); if (!filePath || typeof filePath !== 'string') return; - const editorValues = {}; + const editorValues: EditorValues = {}; const files: [string, string][] = Object.entries( await readFiddle(filePath, true), ); @@ -115,7 +117,7 @@ export class FileManager { } if (isKnownFile(name) || (await app.remoteLoader.confirmAddFile(name))) { - editorValues[name] = value; + editorValues[name as EditorId] = value; } } @@ -185,7 +187,7 @@ export class FileManager { let output: Files = new Map(Object.entries(values)); - output.set(PACKAGE_NAME, values[PACKAGE_NAME]!); + output.set(PACKAGE_NAME, values[PACKAGE_NAME as EditorId]!); for (const transform of transforms) { try { diff --git a/src/renderer/remote-loader.ts b/src/renderer/remote-loader.ts index 8ce208c76b..1b454d5554 100644 --- a/src/renderer/remote-loader.ts +++ b/src/renderer/remote-loader.ts @@ -1,6 +1,7 @@ import semver from 'semver'; import { + EditorId, EditorValues, ElectronReleaseChannel, GenericDialogType, @@ -27,7 +28,7 @@ export class RemoteLoader { 'setElectronVersion', 'verifyReleaseChannelEnabled', 'verifyRemoteLoad', - ]) { + ] as const) { this[name] = this[name].bind(this); } } @@ -100,7 +101,7 @@ export class RemoteLoader { fetch(child.download_url) .then((r) => r.text()) .then((t) => { - values[child.name] = t; + values[child.name as EditorId] = t; }), ); } diff --git a/src/renderer/themes.ts b/src/renderer/themes.ts index 7b5fc24952..644e8fdf54 100644 --- a/src/renderer/themes.ts +++ b/src/renderer/themes.ts @@ -43,7 +43,7 @@ export async function getTheme( async function getCssStringForTheme(theme: FiddleTheme): Promise { let cssContent = ''; - Object.keys(theme.common).forEach((key) => { + Object.keys(theme.common).forEach((key: keyof typeof theme.common) => { cssContent += ` --${key}: ${theme.common[key]};\n`; }); diff --git a/src/utils/editor-utils.ts b/src/utils/editor-utils.ts index 90d6eaa6fb..1524d82b6a 100644 --- a/src/utils/editor-utils.ts +++ b/src/utils/editor-utils.ts @@ -9,7 +9,11 @@ const EMPTY_EDITOR_CONTENT = { } as const; export function getEmptyContent(filename: string): string { - return EMPTY_EDITOR_CONTENT[getSuffix(filename)] || ''; + return ( + EMPTY_EDITOR_CONTENT[ + getSuffix(filename) as keyof typeof EMPTY_EDITOR_CONTENT + ] || '' + ); } export function isRequiredFile(id: EditorId) { @@ -27,6 +31,6 @@ export function getSuffix(filename: string) { return filename.slice(filename.lastIndexOf('.') + 1); } -export function isSupportedFile(filename: string): boolean { +export function isSupportedFile(filename: string): filename is EditorId { return /\.(css|html|js)$/i.test(filename); } diff --git a/src/utils/read-fiddle.ts b/src/utils/read-fiddle.ts index 2c197442e8..9e36c21797 100644 --- a/src/utils/read-fiddle.ts +++ b/src/utils/read-fiddle.ts @@ -2,7 +2,7 @@ import * as path from 'node:path'; import * as fs from 'fs-extra'; -import { EditorValues, PACKAGE_NAME } from '../interfaces'; +import { EditorId, EditorValues, PACKAGE_NAME } from '../interfaces'; import { ensureRequiredFiles, isSupportedFile } from './editor-utils'; /** @@ -31,7 +31,7 @@ export async function readFiddle( ); for (let i = 0; i < names.length; ++i) { - const name = names[i]; + const name = names[i] as EditorId; const value = values[i]; if (value.status === 'fulfilled') { diff --git a/tests/mocks/electron-versions.ts b/tests/mocks/electron-versions.ts index 93f18f6555..1210386602 100644 --- a/tests/mocks/electron-versions.ts +++ b/tests/mocks/electron-versions.ts @@ -17,7 +17,7 @@ export class VersionsMock { version, })); - const obj = {}; + const obj: Record = {}; for (const ver of arr) { obj[ver.version] = ver; } diff --git a/tests/mocks/state.ts b/tests/mocks/state.ts index 757e2b5874..3e6cf80dc1 100644 --- a/tests/mocks/state.ts +++ b/tests/mocks/state.ts @@ -181,11 +181,13 @@ export class StateMock { [ver.version, ver.source, ver.state].join(' '); for (const [key, val] of Object.entries(o)) { if (key == 'currentElectronVersion') { - o[key] = terserRunnable(val) as any; + o[key] = terserRunnable(val as RunnableVersion); } else if (key === 'versions') { - o[key] = Object.values(val).map(terserRunnable) as any; + o[key] = Object.values(val as Record).map( + terserRunnable, + ); } else if (key === 'versionsToShow') { - o[key] = val.map(terserRunnable); + o[key] = (val as Array).map(terserRunnable); } } diff --git a/tests/renderer/bisect-spec.ts b/tests/renderer/bisect-spec.ts index 60eecb4c5f..7fa873731e 100644 --- a/tests/renderer/bisect-spec.ts +++ b/tests/renderer/bisect-spec.ts @@ -48,16 +48,20 @@ describe('bisect', () => { expect(bisector.revList.length).toBe(2); const responseGood = bisector.continue(true); expect(responseGood).toHaveLength(2); - expect(versions).toContain(responseGood[0]); - expect(versions).toContain(responseGood[1]); + if (Array.isArray(responseGood)) { + expect(versions).toContain(responseGood[0]); + expect(versions).toContain(responseGood[1]); + } bisector = new Bisector(versions); expect(bisector.revList.length).toBe(2); const responseBad = bisector.continue(false); expect(responseBad).toHaveLength(2); - expect(versions).toContain(responseBad[0]); - expect(versions).toContain(responseBad[1]); + if (Array.isArray(responseBad)) { + expect(versions).toContain(responseBad[0]); + expect(versions).toContain(responseBad[1]); + } }); }); diff --git a/tests/renderer/editor-mosaic-spec.ts b/tests/renderer/editor-mosaic-spec.ts index aaeccc27ac..0c4f67867a 100644 --- a/tests/renderer/editor-mosaic-spec.ts +++ b/tests/renderer/editor-mosaic-spec.ts @@ -227,7 +227,7 @@ describe('EditorMosaic', () => { // now modify values _after_ calling editorMosaic.set() for (const [file, value] of Object.entries(values)) { - values[file] = `${value} plus more text`; + values[file as EditorId] = `${value} plus more text`; } // and then add Monaco editors diff --git a/tests/renderer/remote-loader-spec.ts b/tests/renderer/remote-loader-spec.ts index 4d950d3ad6..4a044e4d48 100644 --- a/tests/renderer/remote-loader-spec.ts +++ b/tests/renderer/remote-loader-spec.ts @@ -276,7 +276,7 @@ describe('RemoteLoader', () => { await instance.fetchExampleAndLoad('v4.0.0', 'test/path'); - const expectedValues = {}; + const expectedValues: Record = {}; for (const filename of Object.keys(mockGistFiles)) { expectedValues[filename] = filename; } diff --git a/tests/utils.ts b/tests/utils.ts index 8c5cd3651f..e4874e4ef8 100644 --- a/tests/utils.ts +++ b/tests/utils.ts @@ -90,10 +90,10 @@ export class FetchMock { } // return an object containing props in 'a' that are different from in 'b' -export function objectDifference(a: Type, b: Type): Type { +export function objectDifference(a: any, b: any): Record { const serialize = (input: any) => JSON.stringify(toJS(input)); - const o = {}; + const o: Record = {}; for (const entry of Object.entries(a)) { const key = entry[0]; const val = toJS(entry[1]); @@ -101,7 +101,7 @@ export function objectDifference(a: Type, b: Type): Type { o[key] = key === 'editorMosaic' ? objectDifference(val, b[key]) : toJS(val); } - return o as Type; + return o; } /** diff --git a/tests/utils/read-fiddle-spec.ts b/tests/utils/read-fiddle-spec.ts index e47cdfe3b0..27dc572ee5 100644 --- a/tests/utils/read-fiddle-spec.ts +++ b/tests/utils/read-fiddle-spec.ts @@ -2,7 +2,7 @@ import * as path from 'node:path'; import * as fs from 'fs-extra'; -import { EditorValues, MAIN_JS } from '../../src/interfaces'; +import { EditorId, EditorValues, MAIN_JS } from '../../src/interfaces'; import { ensureRequiredFiles, getEmptyContent, @@ -26,7 +26,7 @@ describe('read-fiddle', () => { function setupFSMocks(editorValues: EditorValues) { (fs.readdir as jest.Mock).mockResolvedValue(Object.keys(editorValues)); (fs.readFile as jest.Mock).mockImplementation( - async (filename) => editorValues[path.basename(filename)], + async (filename) => editorValues[path.basename(filename) as EditorId], ); } diff --git a/tsconfig.json b/tsconfig.json index 3b3e042599..8c7e636cfb 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -16,7 +16,6 @@ ], "noImplicitAny": true, "noImplicitReturns": true, - "suppressImplicitAnyIndexErrors": true, "strictNullChecks": true, "noUnusedLocals": true, "noImplicitThis": true, diff --git a/yarn.lock b/yarn.lock index 9d3723edea..f71d61d4d6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5612,10 +5612,10 @@ follow-redirects@^1.0.0: resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz" integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== -fork-ts-checker-webpack-plugin@^7.2.11: - version "7.2.13" - resolved "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-7.2.13.tgz" - integrity sha512-fR3WRkOb4bQdWB/y7ssDUlVdrclvwtyCUIHCfivAoYxq9dF7XfrDKbMdZIfwJ7hxIAqkYSGeU7lLJE6xrxIBdg== +fork-ts-checker-webpack-plugin@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-8.0.0.tgz#dae45dfe7298aa5d553e2580096ced79b6179504" + integrity sha512-mX3qW3idpueT2klaQXBzrIM/pHw+T0B/V9KHEvNrqijTq9NFnMZU6oreVxDYcf33P8a5cW+67PjodNHthGnNVg== dependencies: "@babel/code-frame" "^7.16.7" chalk "^4.1.2" @@ -11174,10 +11174,10 @@ ts-jest@^29.1.1: semver "^7.5.3" yargs-parser "^21.0.1" -ts-loader@^9.3.1: - version "9.3.1" - resolved "https://registry.npmjs.org/ts-loader/-/ts-loader-9.3.1.tgz" - integrity sha512-OkyShkcZTsTwyS3Kt7a4rsT/t2qvEVQuKCTg4LJmpj9fhFR7ukGdZwV6Qq3tRUkqcXtfGpPR7+hFKHCG/0d3Lw== +ts-loader@^9.4.4: + version "9.4.4" + resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-9.4.4.tgz#6ceaf4d58dcc6979f84125335904920884b7cee4" + integrity sha512-MLukxDHBl8OJ5Dk3y69IsKVFRA/6MwzEqBgh+OXMPB/OD01KQuWPFd1WAQP8a5PeSCAxfnkhiuWqfmFJzJQt9w== dependencies: chalk "^4.1.0" enhanced-resolve "^5.0.0" @@ -11224,6 +11224,11 @@ tslib@^2.4.0: resolved "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz" integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== +tslib@^2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.0.tgz#b295854684dbda164e181d259a22cd779dcd7bc3" + integrity sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA== + tslib@~1.13.0: version "1.13.0" resolved "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz" @@ -11291,10 +11296,10 @@ typed-styles@^0.0.7: resolved "https://registry.npmjs.org/typed-styles/-/typed-styles-0.0.7.tgz" integrity sha512-pzP0PWoZUhsECYjABgCGQlRGL1n7tOHsgwYv3oIiEpJwGhFTuty/YNeduxQYzXXa3Ge5BdT6sHYIQYpl4uJ+5Q== -typescript@~4.3.0: - version "4.3.5" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.5.tgz#4d1c37cc16e893973c45a06886b7113234f119f4" - integrity sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA== +typescript@^5.1.6: + version "5.1.6" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.1.6.tgz#02f8ac202b6dad2c0dd5e0913745b47a37998274" + integrity sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA== uc.micro@^1.0.1, uc.micro@^1.0.5: version "1.0.6"