From 47edae185a87437b75c9403a86d93a77c9d1da28 Mon Sep 17 00:00:00 2001 From: pratik-londhe4 Date: Thu, 11 Jun 2026 00:11:43 +0530 Subject: [PATCH 1/5] TypeScript tooling support --- package-lock.json | 81 ++++++++++++++++++++--------------------------- package.json | 6 ++++ src/global.d.ts | 2 ++ tsconfig.json | 66 ++++++++++++++++++++++++++++++++++++++ webpack.config.js | 4 +-- 5 files changed, 111 insertions(+), 48 deletions(-) create mode 100644 src/global.d.ts create mode 100644 tsconfig.json diff --git a/package-lock.json b/package-lock.json index 23e480be..a17408c4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,12 +14,10 @@ "devDependencies": { "@babel/core": "7.29.7", "@eslint-community/eslint-plugin-eslint-comments": "4.7.2", - "@types/jest": "^29.5.14", - "@types/node": "^22.10.0", + "@types/jest": "29.5.14", + "@types/react": "18.3.31", + "@types/react-dom": "18.3.7", "@types/wordpress__block-editor": "15.0.6", - "@types/wordpress__i18n": "3.11.0", - "@typescript-eslint/eslint-plugin": "^8.20.0", - "@typescript-eslint/parser": "^8.20.0", "@wordpress/babel-preset-default": "8.47.0", "@wordpress/browserslist-config": "6.47.0", "@wordpress/env": "11.7.0", @@ -42,7 +40,7 @@ "npm-run-all": "4.1.5", "rtlcss": "4.3.0", "svgo": "4.0.1", - "typescript": "^5.7.0", + "typescript": "6.0.3", "webpack": "5.107.2", "webpack-remove-empty-scripts": "1.1.1" } @@ -8659,23 +8657,24 @@ "license": "MIT" }, "node_modules/@types/react": { - "version": "19.2.16", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.16.tgz", - "integrity": "sha512-esJiCAnl0kfpNdE69f3So4WJUXy95dLZydX0KwK46riIHDzHM7O9Vtf9xCHW0PXIqvgqNrswl522kA/5yx+F4w==", + "version": "18.3.31", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.31.tgz", + "integrity": "sha512-vfEqpXTvwT91yhmwdfouStN2hSKwTvyRs8qpLfADyrq/kxDw0hZM7Wk9Ug1FELj8hIby+S/+kQCSRFF32nv2Qw==", "dev": true, "license": "MIT", "dependencies": { + "@types/prop-types": "*", "csstype": "^3.2.2" } }, "node_modules/@types/react-dom": { - "version": "19.2.3", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", - "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "version": "18.3.7", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", + "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", "dev": true, "license": "MIT", "peerDependencies": { - "@types/react": "^19.2.0" + "@types/react": "^18.0.0" } }, "node_modules/@types/responselike": { @@ -8796,25 +8795,6 @@ "react-autosize-textarea": "^7.1.0" } }, - "node_modules/@types/wordpress__block-editor/node_modules/@types/react": { - "version": "18.3.30", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.30.tgz", - "integrity": "sha512-3ek6mwJL5/VBewBcY4S66cqlCtK3qi4WIq37Z0m/NHw1hjhI7274Mx1qz/+ggSzyBCOEf7eHjBN6INjPAWYfYw==", - "dev": true, - "dependencies": { - "@types/prop-types": "*", - "csstype": "^3.2.2" - } - }, - "node_modules/@types/wordpress__block-editor/node_modules/@types/react-dom": { - "version": "18.3.7", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", - "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", - "dev": true, - "peerDependencies": { - "@types/react": "^18.0.0" - } - }, "node_modules/@types/wordpress__block-editor/node_modules/@wordpress/base-styles": { "version": "6.20.0", "resolved": "https://registry.npmjs.org/@wordpress/base-styles/-/base-styles-6.20.0.tgz", @@ -9020,17 +9000,6 @@ "uuid": "dist/bin/uuid" } }, - "node_modules/@types/wordpress__i18n": { - "version": "3.11.0", - "resolved": "https://registry.npmjs.org/@types/wordpress__i18n/-/wordpress__i18n-3.11.0.tgz", - "integrity": "sha512-l4OXE1LQH7IBqRXY//NGBCsM0jPv8sdUEubPaAzPxKUxYGe+I2UTREjwB0ejuh2+J0p90EhW3mX5FYM8a8lf2w==", - "deprecated": "This is a stub types definition. wordpress__i18n provides its own type definitions, so you do not need this installed.", - "dev": true, - "license": "MIT", - "dependencies": { - "@wordpress/i18n": "*" - } - }, "node_modules/@types/ws": { "version": "8.18.1", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", @@ -10182,6 +10151,26 @@ "npm": ">=8.19.2" } }, + "node_modules/@wordpress/element/node_modules/@types/react": { + "version": "19.2.17", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.17.tgz", + "integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==", + "dev": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@wordpress/element/node_modules/@types/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, "node_modules/@wordpress/env": { "version": "11.7.0", "resolved": "https://registry.npmjs.org/@wordpress/env/-/env-11.7.0.tgz", @@ -32991,9 +32980,9 @@ "license": "MIT" }, "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", "dev": true, "license": "Apache-2.0", "bin": { diff --git a/package.json b/package.json index 87d34c23..8ebc7b28 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,10 @@ "devDependencies": { "@babel/core": "7.29.7", "@eslint-community/eslint-plugin-eslint-comments": "4.7.2", + "@types/jest": "29.5.14", + "@types/react": "18.3.31", + "@types/react-dom": "18.3.7", + "@types/wordpress__block-editor": "15.0.6", "@wordpress/babel-preset-default": "8.47.0", "@wordpress/browserslist-config": "6.47.0", "@wordpress/env": "11.7.0", @@ -34,6 +38,7 @@ "npm-run-all": "4.1.5", "rtlcss": "4.3.0", "svgo": "4.0.1", + "typescript": "6.0.3", "webpack": "5.107.2", "webpack-remove-empty-scripts": "1.1.1" }, @@ -69,6 +74,7 @@ "lint:js": "wp-scripts lint-js ./src", "lint:js:fix": "npm run lint:js -- --fix", "lint:js:report": "npm run lint:js -- --output-file lint-js-report.json --format json .", + "lint:js:types": "tsc --noEmit", "lint:package-json": "wp-scripts lint-pkg-json --ignorePath .gitignore", "lint:php": "php vendor/bin/phpcs", "lint:php:fix": "node ./bin/phpcbf.js", diff --git a/src/global.d.ts b/src/global.d.ts new file mode 100644 index 00000000..34284238 --- /dev/null +++ b/src/global.d.ts @@ -0,0 +1,2 @@ +declare module '*.scss'; +declare module '*.css'; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..f49418f8 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,66 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig.json", + + "compilerOptions": { + "allowJs": true, + // Migration override — flip to true once src/ is fully .ts/.tsx. + "checkJs": false, + + // Type checking — full strict. + "strict": true, + "allowUnreachableCode": false, + "allowUnusedLabels": false, + "exactOptionalPropertyTypes": true, + "forceConsistentCasingInFileNames": true, + "noErrorTruncation": true, + "noFallthroughCasesInSwitch": true, + "noImplicitOverride": true, + "noImplicitReturns": true, + "noPropertyAccessFromIndexSignature": true, + "noUncheckedIndexedAccess": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + + // Modules + "module": "preserve", + "moduleResolution": "bundler", + "resolveJsonModule": true, + + // Interop Constraints + "esModuleInterop": true, + "isolatedModules": true, + // @todo flip to true once package.json declares `"type": "module"`. + "verbatimModuleSyntax": false, + + // Language and Environment + "jsx": "react-jsx", + "lib": [ "ES2022", "DOM.Iterable", "DOM" ], + "moduleDetection": "force", + "target": "ES2022", + + // Completeness + "skipLibCheck": true, + + // Project-specific + "noEmit": true, + "paths": { + "@/*": [ "./src/*" ] + }, + // Jest globals stay out of src/; tests get their own tsconfig once they migrate. + "types": [ "node" ] + }, + "include": [ + "src/**/*", + "tests/**/*", + "webpack.config.js", + "webpack.blocks.config.js", + "babel.config.js" + ], + "exclude": [ + "node_modules", + "vendor", + "assets/build", + "build", + "bin" + ] +} diff --git a/webpack.config.js b/webpack.config.js index 39bcd742..1f9ae6be 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -530,10 +530,10 @@ const scripts = { ], }; -// Component JS entry points from src/components/{component}/{component}.js. +// Component script entry points from src/components/{component}/{component}.{js,jsx,ts,tsx}. const componentScripts = { ...sharedNonHotConfig, - entry: () => getComponentEntries( COMPONENTS_DIR, /\.js$/ ), + entry: () => getComponentEntries( COMPONENTS_DIR, /\.(jsx?|tsx?)$/ ), plugins: [ ...sharedNonHotConfig.plugins.filter( isNotPlugin( 'RtlCssPlugin' ) ), ], From 53cd6f821678a3490f530eff8380fefe077c3504 Mon Sep 17 00:00:00 2001 From: pratik-londhe4 Date: Thu, 11 Jun 2026 00:22:45 +0530 Subject: [PATCH 2/5] Scope lint-style to only scan stylesheet files --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8ebc7b28..0499035d 100644 --- a/package.json +++ b/package.json @@ -69,7 +69,7 @@ "init": "./bin/init.js && npm run sync-ai", "sync-ai": "node bin/sync-ai.js", "lint:all": "npm-run-all --parallel lint:*", - "lint:css": "wp-scripts lint-style ./src", + "lint:css": "wp-scripts lint-style './src/**/*.{css,scss}'", "lint:css:fix": "npm run lint:css -- --fix", "lint:js": "wp-scripts lint-js ./src", "lint:js:fix": "npm run lint:js -- --fix", From bc8598cafbd7dfa5da279c348ada03d3f1ca2592 Mon Sep 17 00:00:00 2001 From: pratik-londhe4 Date: Thu, 11 Jun 2026 00:35:08 +0530 Subject: [PATCH 3/5] refactor: migrate theme source scripts to TypeScript --- .../button/{button.js => button.ts} | 0 ...{core-navigation.js => core-navigation.ts} | 0 .../modules/{media-text.js => media-text.ts} | 21 +++++++++++-------- 3 files changed, 12 insertions(+), 9 deletions(-) rename src/components/button/{button.js => button.ts} (100%) rename src/js/frontend/{core-navigation.js => core-navigation.ts} (100%) rename src/js/frontend/modules/{media-text.js => media-text.ts} (59%) diff --git a/src/components/button/button.js b/src/components/button/button.ts similarity index 100% rename from src/components/button/button.js rename to src/components/button/button.ts diff --git a/src/js/frontend/core-navigation.js b/src/js/frontend/core-navigation.ts similarity index 100% rename from src/js/frontend/core-navigation.js rename to src/js/frontend/core-navigation.ts diff --git a/src/js/frontend/modules/media-text.js b/src/js/frontend/modules/media-text.ts similarity index 59% rename from src/js/frontend/modules/media-text.js rename to src/js/frontend/modules/media-text.ts index 4e8d56ca..ac8a5769 100644 --- a/src/js/frontend/modules/media-text.js +++ b/src/js/frontend/modules/media-text.ts @@ -7,29 +7,32 @@ */ import { store, getContext, getElement } from '@wordpress/interactivity'; +/** + * Shape of the per-element context (set via `data-wp-context` in the markup). + */ +interface MediaTextContext { + isPlaying: boolean; +} + store( 'elementary/media-text', { actions: { /** * Update the video play state. - * - * @return {void} */ - play() { - const context = getContext(); + play(): void { + const context = getContext< MediaTextContext >(); context.isPlaying = true; }, }, callbacks: { /** * Play the video. - * - * @return {void} */ - playVideo() { - const context = getContext(); + playVideo(): void { + const context = getContext< MediaTextContext >(); const { ref } = getElement(); if ( context.isPlaying ) { - ref.querySelector( 'video' )?.play(); + ref?.querySelector( 'video' )?.play(); context.isPlaying = false; } }, From a2d255e1b64fb6971000b64c997d5e3251744252 Mon Sep 17 00:00:00 2001 From: pratik-londhe4 Date: Thu, 11 Jun 2026 14:04:26 +0530 Subject: [PATCH 4/5] Add webpack test for typescript files as well: --- package-lock.json | 45 +++++------------------- package.json | 8 +++-- src/components/card/{card.js => card.ts} | 0 tests/js/webpack-config.test.js | 29 +++++++++++++++ 4 files changed, 43 insertions(+), 39 deletions(-) rename src/components/card/{card.js => card.ts} (100%) diff --git a/package-lock.json b/package-lock.json index a17408c4..9e537a42 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,8 +15,8 @@ "@babel/core": "7.29.7", "@eslint-community/eslint-plugin-eslint-comments": "4.7.2", "@types/jest": "29.5.14", - "@types/react": "18.3.31", - "@types/react-dom": "18.3.7", + "@types/react": "19.2.17", + "@types/react-dom": "19.2.3", "@types/wordpress__block-editor": "15.0.6", "@wordpress/babel-preset-default": "8.47.0", "@wordpress/browserslist-config": "6.47.0", @@ -8636,12 +8636,6 @@ "@types/pg": "*" } }, - "node_modules/@types/prop-types": { - "version": "15.7.15", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", - "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", - "dev": true - }, "node_modules/@types/qs": { "version": "6.15.1", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.15.1.tgz", @@ -8657,24 +8651,23 @@ "license": "MIT" }, "node_modules/@types/react": { - "version": "18.3.31", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.31.tgz", - "integrity": "sha512-vfEqpXTvwT91yhmwdfouStN2hSKwTvyRs8qpLfADyrq/kxDw0hZM7Wk9Ug1FELj8hIby+S/+kQCSRFF32nv2Qw==", + "version": "19.2.17", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.17.tgz", + "integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==", "dev": true, "license": "MIT", "dependencies": { - "@types/prop-types": "*", "csstype": "^3.2.2" } }, "node_modules/@types/react-dom": { - "version": "18.3.7", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", - "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", "dev": true, "license": "MIT", "peerDependencies": { - "@types/react": "^18.0.0" + "@types/react": "^19.2.0" } }, "node_modules/@types/responselike": { @@ -10151,26 +10144,6 @@ "npm": ">=8.19.2" } }, - "node_modules/@wordpress/element/node_modules/@types/react": { - "version": "19.2.17", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.17.tgz", - "integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==", - "dev": true, - "license": "MIT", - "dependencies": { - "csstype": "^3.2.2" - } - }, - "node_modules/@wordpress/element/node_modules/@types/react-dom": { - "version": "19.2.3", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", - "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@types/react": "^19.2.0" - } - }, "node_modules/@wordpress/env": { "version": "11.7.0", "resolved": "https://registry.npmjs.org/@wordpress/env/-/env-11.7.0.tgz", diff --git a/package.json b/package.json index 0499035d..738863b0 100644 --- a/package.json +++ b/package.json @@ -13,8 +13,8 @@ "@babel/core": "7.29.7", "@eslint-community/eslint-plugin-eslint-comments": "4.7.2", "@types/jest": "29.5.14", - "@types/react": "18.3.31", - "@types/react-dom": "18.3.7", + "@types/react": "19.2.17", + "@types/react-dom": "19.2.3", "@types/wordpress__block-editor": "15.0.6", "@wordpress/babel-preset-default": "8.47.0", "@wordpress/browserslist-config": "6.47.0", @@ -52,7 +52,9 @@ "overrides": { "webpack-dev-server": "5.2.1", "serialize-javascript": "7.0.3", - "minimatch": "3.1.3" + "minimatch": "3.1.3", + "@types/react": "$@types/react", + "@types/react-dom": "$@types/react-dom" }, "private": true, "repository": { diff --git a/src/components/card/card.js b/src/components/card/card.ts similarity index 100% rename from src/components/card/card.js rename to src/components/card/card.ts diff --git a/tests/js/webpack-config.test.js b/tests/js/webpack-config.test.js index a5b458ca..d763e05c 100644 --- a/tests/js/webpack-config.test.js +++ b/tests/js/webpack-config.test.js @@ -45,4 +45,33 @@ describe( 'webpack component entries', () => { 'components/button': path.join( buttonDir, 'button.js' ), } ); } ); + + it( 'picks up .ts and .tsx component entries with the build pattern', () => { + tmpDir = fs.mkdtempSync( + path.join( os.tmpdir(), 'elementary-webpack-components-ts-' ) + ); + + const cardDir = path.join( tmpDir, 'card' ); + const modalDir = path.join( tmpDir, 'modal' ); + const legacyDir = path.join( tmpDir, 'legacy' ); + + [ cardDir, modalDir, legacyDir ].forEach( ( dir ) => fs.mkdirSync( dir ) ); + + // One entry per supported extension. + fs.writeFileSync( path.join( cardDir, 'card.ts' ), '' ); + fs.writeFileSync( path.join( modalDir, 'modal.tsx' ), '' ); + fs.writeFileSync( path.join( legacyDir, 'legacy.js' ), '' ); + + // Same-folder files that must NOT become entries (basename mismatch), + // even though their extensions match the widened pattern. + fs.writeFileSync( path.join( cardDir, 'card.types.ts' ), '' ); + fs.writeFileSync( path.join( cardDir, 'card.test.tsx' ), '' ); + + // Mirrors the pattern used by componentScripts in webpack.config.js. + expect( getComponentEntries( tmpDir, /\.(jsx?|tsx?)$/ ) ).toEqual( { + 'components/card': path.join( cardDir, 'card.ts' ), + 'components/modal': path.join( modalDir, 'modal.tsx' ), + 'components/legacy': path.join( legacyDir, 'legacy.js' ), + } ); + } ); } ); From 444e9b44057137a35637cc22836e35fe508c68a5 Mon Sep 17 00:00:00 2001 From: pratik-londhe4 Date: Thu, 11 Jun 2026 14:26:42 +0530 Subject: [PATCH 5/5] Update eslint config to support linting TS files --- eslint.config.mjs | 40 +++++++++++++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/eslint.config.mjs b/eslint.config.mjs index 731dece0..2bf35beb 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -8,12 +8,13 @@ import wordpressPlugin from '@wordpress/eslint-plugin'; import comments from '@eslint-community/eslint-plugin-eslint-comments/configs'; import jestPlugin from 'eslint-plugin-jest'; import globals from 'globals'; +import tseslint from 'typescript-eslint'; const TEST_FILES = [ - '**/__tests__/**/*.js', - '**/test/*.js', - '**/?(*.)test.js', - 'tests/js/**/*.js', + '**/__tests__/**/*.{js,ts,tsx}', + '**/test/*.{js,ts,tsx}', + '**/?(*.)test.{js,ts,tsx}', + 'tests/js/**/*.{js,ts,tsx}', ]; export default [ @@ -28,6 +29,30 @@ export default [ ...wordpressPlugin.configs[ 'recommended-with-formatting' ], + // `recommended-with-formatting` (unlike `recommended`) doesn't register a + // TypeScript config, so `.ts`/`.tsx` would be unmatched and skipped. Add the + // TypeScript parser + the unused-vars handoff, mirroring the TS block in + // @wordpress/eslint-plugin's `recommended` preset. + { + files: [ '**/*.ts', '**/*.tsx' ], + languageOptions: { + parser: tseslint.parser, + }, + plugins: { + '@typescript-eslint': tseslint.plugin, + }, + rules: { + 'no-duplicate-imports': 'off', + 'jsdoc/require-param-type': 'off', + 'jsdoc/require-returns-type': 'off', + 'no-unused-vars': 'off', + '@typescript-eslint/no-unused-vars': [ + 'error', + { ignoreRestSiblings: true }, + ], + }, + }, + // import plugin is already registered by the WordPress config above; // add the remaining rules from plugin:import/recommended without re-registering. { @@ -65,7 +90,12 @@ export default [ { settings: { - 'import/resolver': { node: true }, + 'import/resolver': { + typescript: { + extensions: [ '.js', '.jsx', '.ts', '.tsx' ], + }, + node: true, + }, }, }, ];