diff --git a/README.rst b/README.rst
index d4bc758f4..e7e044bcd 100644
--- a/README.rst
+++ b/README.rst
@@ -157,6 +157,14 @@ You may create a `.env.private` with any overrides of the environment settings c
**Note: .env.private should be added to your project's .gitignore so it does not get checked in.**
+Local module configuration for TypeScript
+-----------------------------------------
+
+#. Copy tsconfig.json into the root of the module
+#. Set "rootDir" to the root of the source code folders
+#. Set "include" to wildcard patterns specifying the subdirectories/files under rootDir where source code can be found
+#. Include any wildcards under rootDir that should be excluded using "exclude"
+
Development
-----------
diff --git a/config/jest.config.js b/config/jest.config.js
index ae08b706f..716c0e10c 100644
--- a/config/jest.config.js
+++ b/config/jest.config.js
@@ -1,5 +1,6 @@
const path = require('path');
const fs = require('fs');
+const { jsWithTs: tsjPreset } = require('ts-jest/presets');
const presets = require('../lib/presets');
@@ -33,11 +34,12 @@ module.exports = {
'/node_modules/(?!@edx)',
],
transform: {
- '^.+\\.[t|j]sx?$': [
+ '^.+\\.jsx?$': [
'babel-jest',
{
configFile: presets.babel.resolvedFilepath,
},
],
+ ...tsjPreset.transform,
},
};
diff --git a/config/webpack.common.config.js b/config/webpack.common.config.js
index 62c3aa348..8490a665c 100644
--- a/config/webpack.common.config.js
+++ b/config/webpack.common.config.js
@@ -17,6 +17,6 @@ module.exports = {
// the application being built.
'env.config': false,
},
- extensions: ['.js', '.jsx'],
+ extensions: ['.js', '.jsx', '.ts', '.tsx'],
},
};
diff --git a/config/webpack.prod.config.js b/config/webpack.prod.config.js
index 8634a4f9a..2db9ba5b1 100644
--- a/config/webpack.prod.config.js
+++ b/config/webpack.prod.config.js
@@ -71,12 +71,12 @@ module.exports = merge(commonConfig, {
// The babel-loader transforms newer ES2015+ syntax to older ES5 for older browsers.
// Babel is configured with the .babelrc file at the root of the project.
{
- test: /\.(js|jsx)$/,
+ test: /\.(js|jsx|ts|tsx)$/,
exclude: /node_modules\/(?!@edx)/,
use: {
loader: 'babel-loader',
options: {
- configFile: presets.babel.resolvedFilepath,
+ configFile: presets['babel-typescript'].resolvedFilepath,
},
},
},
diff --git a/example/src/App.jsx b/example/src/App.jsx
index 2f1346339..8ef1e4417 100644
--- a/example/src/App.jsx
+++ b/example/src/App.jsx
@@ -1,4 +1,5 @@
import config from 'env.config';
+import Image from './Image';
import appleUrl, { ReactComponent as Apple } from './apple.svg';
import appleImg from './apple.jpg';
@@ -19,6 +20,8 @@ export default function App() {
JSX parsing tests
+ TSX parsing tests
+
Asset import tests
diff --git a/example/src/Image.tsx b/example/src/Image.tsx
new file mode 100644
index 000000000..a8e7531e1
--- /dev/null
+++ b/example/src/Image.tsx
@@ -0,0 +1,11 @@
+import React, { CSSProperties } from "react";
+
+type ImageProps = {
+ src: string;
+ alt?: string;
+ style?: CSSProperties;
+};
+
+export default function Image(props:ImageProps) {
+ return ;
+}
diff --git a/example/src/__snapshots__/App.test.jsx.snap b/example/src/__snapshots__/App.test.jsx.snap
index 5666dd15d..551869852 100644
--- a/example/src/__snapshots__/App.test.jsx.snap
+++ b/example/src/__snapshots__/App.test.jsx.snap
@@ -39,6 +39,18 @@ exports[`Basic test should render 1`] = `
}
}
/>
+
+ TSX parsing tests
+
+
Asset import tests
diff --git a/package-lock.json b/package-lock.json
index 4c520dd03..cc5410d64 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -19,9 +19,11 @@
"@babel/preset-react": "7.18.6",
"@edx/eslint-config": "3.1.1",
"@edx/new-relic-source-map-webpack-plugin": "1.0.2",
+ "@edx/typescript-config": "^1.0.0",
"@fullhuman/postcss-purgecss": "^5.0.0",
"@pmmmwh/react-refresh-webpack-plugin": "0.5.10",
"@svgr/webpack": "6.5.1",
+ "@types/jest": "^26.0.0",
"autoprefixer": "10.4.14",
"babel-jest": "26.6.3",
"babel-loader": "9.1.2",
@@ -57,6 +59,8 @@
"sharp": "^0.31.0",
"source-map-loader": "^4.0.1",
"style-loader": "3.3.2",
+ "ts-jest": "^26.5.0",
+ "typescript": "^4.9.4",
"url-loader": "4.1.1",
"webpack": "5.76.0",
"webpack-bundle-analyzer": "4.5.0",
@@ -1949,6 +1953,16 @@
"@newrelic/publish-sourcemap": "^5.0.1"
}
},
+ "node_modules/@edx/typescript-config": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@edx/typescript-config/-/typescript-config-1.0.0.tgz",
+ "integrity": "sha512-4Iip/UZyJ/Kn6fMbtzjpltTEssRdaeseYQAxiCeFOp3l5I6/Kt54UTQSYFYZtd8KtKSYNfXNXe1PqsZjYQf55w==",
+ "peerDependencies": {
+ "@types/jest": "^26.0.0",
+ "ts-jest": "^26.5.0",
+ "typescript": "^4.9.4"
+ }
+ },
"node_modules/@eslint/eslintrc": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz",
@@ -3471,6 +3485,15 @@
"@types/istanbul-lib-report": "*"
}
},
+ "node_modules/@types/jest": {
+ "version": "26.0.24",
+ "resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.24.tgz",
+ "integrity": "sha512-E/X5Vib8BWqZNRlDxj9vYXhsDwPYbPINqKF9BsnSoon4RQ0D9moEuLD8txgyypFLH7J4+Lho9Nr/c8H0Fi+17w==",
+ "dependencies": {
+ "jest-diff": "^26.0.0",
+ "pretty-format": "^26.0.0"
+ }
+ },
"node_modules/@types/json-schema": {
"version": "7.0.11",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz",
@@ -4870,8 +4893,6 @@
"version": "0.2.6",
"resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz",
"integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==",
- "optional": true,
- "peer": true,
"dependencies": {
"fast-json-stable-stringify": "2.x"
},
@@ -11756,9 +11777,7 @@
"node_modules/make-error": {
"version": "1.3.6",
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
- "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
- "optional": true,
- "peer": true
+ "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw=="
},
"node_modules/makeerror": {
"version": "1.0.12",
@@ -16160,8 +16179,6 @@
"version": "26.5.6",
"resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-26.5.6.tgz",
"integrity": "sha512-rua+rCP8DxpA8b4DQD/6X2HQS8Zy/xzViVYfEs2OQu68tkCuKLV0Md8pmX55+W24uRIyAsf/BajRfxOs+R2MKA==",
- "optional": true,
- "peer": true,
"dependencies": {
"bs-logger": "0.x",
"buffer-from": "1.x",
@@ -16189,8 +16206,6 @@
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
- "optional": true,
- "peer": true,
"dependencies": {
"yallist": "^4.0.0"
},
@@ -16202,8 +16217,6 @@
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
- "optional": true,
- "peer": true,
"bin": {
"mkdirp": "bin/cmd.js"
},
@@ -16215,8 +16228,6 @@
"version": "7.3.8",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
"integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
- "optional": true,
- "peer": true,
"dependencies": {
"lru-cache": "^6.0.0"
},
@@ -16230,9 +16241,7 @@
"node_modules/ts-jest/node_modules/yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
- "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
- "optional": true,
- "peer": true
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
},
"node_modules/tsconfig-paths": {
"version": "3.14.1",
diff --git a/package.json b/package.json
index efb719985..4a8c990a2 100644
--- a/package.json
+++ b/package.json
@@ -35,9 +35,11 @@
"@babel/preset-react": "7.18.6",
"@edx/eslint-config": "3.1.1",
"@edx/new-relic-source-map-webpack-plugin": "1.0.2",
+ "@edx/typescript-config": "^1.0.0",
"@fullhuman/postcss-purgecss": "^5.0.0",
"@pmmmwh/react-refresh-webpack-plugin": "0.5.10",
"@svgr/webpack": "6.5.1",
+ "@types/jest": "^26.0.0",
"autoprefixer": "10.4.14",
"babel-jest": "26.6.3",
"babel-loader": "9.1.2",
@@ -73,6 +75,8 @@
"sharp": "^0.31.0",
"source-map-loader": "^4.0.1",
"style-loader": "3.3.2",
+ "ts-jest": "^26.5.0",
+ "typescript": "^4.9.4",
"url-loader": "4.1.1",
"webpack": "5.76.0",
"webpack-bundle-analyzer": "4.5.0",
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 000000000..d603a1dbf
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,9 @@
+{
+ "extends": "@edx/typescript-config",
+ "compilerOptions": {
+ "rootDir": "example",
+ "outDir": "dist"
+ },
+ "include": ["example/**/*"],
+ "exclude": ["example/dist/*", "example/node_modules/*'"]
+}