Set up TypeScript linting with ESLint
diff --git a/.eslintrc.js b/.eslintrc.js
index 32a4ec9..82a6833 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -31,40 +31,9 @@
 
 module.exports = {
   root: true,
-  env: {
-    es6: true,
-    'shared-node-browser': true,
-  },
-  extends: ['eslint:recommended', 'plugin:import/recommended', 'prettier'],
-  globals: {
-    globalThis: true,
-  },
-  parser: 'babel-eslint',
-  parserOptions: {
-    ecmaVersion: 2020,
-    sourceType: 'module',
-  },
-  plugins: ['import', 'prettier'],
+  extends: ['eslint:recommended', 'prettier'],
+  plugins: ['prettier'],
   rules: {
-    'import/extensions': ['error', 'always', { ignorePackages: true }],
-    'import/first': 'error',
-    'import/newline-after-import': 'error',
-    'import/no-default-export': 'error',
-    'import/no-internal-modules': 'error',
-    'import/no-relative-parent-imports': 'error',
-    'import/order': ['error', { 'newlines-between': 'always' }],
-    'import/unambiguous': 'error',
-    'no-restricted-syntax': [
-      'error',
-      'BindExpression',
-      'ClassProperty',
-      'Decorator',
-      'DoExpression',
-      'ExportDefaultSpecifier',
-      'ExportNamespaceSpecifier',
-      'TypeAnnotation',
-      'JSXElement',
-    ],
     'prettier/prettier': [
       'error',
       {
@@ -73,11 +42,6 @@
       },
     ],
   },
-  settings: {
-    'import/resolver': {
-      'babel-module': babelModuleResolver.options,
-    },
-  },
   overrides: [
     {
       files: [
@@ -88,12 +52,9 @@
         'nyc.config.js',
       ],
       env: {
+        es2017: true,
         node: true,
       },
-      parser: 'espree',
-      parserOptions: {
-        sourceType: 'script',
-      },
       plugins: ['node'],
       rules: {
         'no-console': 'off',
@@ -101,19 +62,69 @@
       },
     },
     {
-      files: ['web/demo/**/*.js'],
+      files: ['**/*.ts'],
       env: {
-        browser: true,
+        es2020: true,
+        'shared-node-browser': true,
+      },
+      extends: [
+        'plugin:@typescript-eslint/recommended',
+        'plugin:@typescript-eslint/recommended-requiring-type-checking',
+        'plugin:import/recommended',
+        'plugin:import/typescript',
+      ],
+      parserOptions: {
+        ecmaVersion: 2020,
+        project: ['./tsconfig.json'],
+        tsconfigRootDir: __dirname,
+      },
+      plugins: ['@typescript-eslint', 'import'],
+      rules: {
+        '@typescript-eslint/explicit-function-return-type': 'off',
+        '@typescript-eslint/no-unused-vars': [
+          'error',
+          { argsIgnorePattern: '^_' },
+        ],
+
+        'import/extensions': [
+          'error',
+          'ignorePackages',
+          {
+            ts: 'never',
+          },
+        ],
+        'import/first': 'error',
+        'import/newline-after-import': 'error',
+        'import/no-default-export': 'error',
+        'import/no-internal-modules': 'error',
+        'import/no-relative-parent-imports': 'error',
+        'import/order': ['error', { 'newlines-between': 'always' }],
+        'import/unambiguous': 'error',
+      },
+      settings: {
+        'import/resolver': {
+          'babel-module': babelModuleResolver.options,
+        },
       },
     },
     {
-      files: ['packages/*/test/**/*.js', 'test/**/*.js'],
+      files: ['**/@types/**/*.d.ts'],
+      rules: {
+        'import/no-default-export': 'off',
+        'import/unambiguous': 'off',
+      },
+    },
+    {
+      files: ['packages/*/test/**/*.ts', 'test/**/*.ts'],
       env: {
         mocha: true,
       },
       globals: {
         assert: true,
       },
+      parserOptions: {
+        project: ['./tsconfig.tests.json'],
+      },
       rules: {
         'import/no-internal-modules': [
           'error',
@@ -128,10 +139,20 @@
       },
     },
     {
-      files: ['packages/dom/{src,test}/**/*.js'],
+      files: ['packages/dom/**/*.js'],
       env: {
         browser: true,
       },
     },
+    {
+      files: ['web/demo/**/*.js'],
+      env: {
+        browser: true,
+        es2020: true,
+      },
+      parserOptions: {
+        sourceType: 'module',
+      },
+    },
   ],
 };
diff --git a/package.json b/package.json
index 190cae1..e30f679 100644
--- a/package.json
+++ b/package.json
@@ -21,7 +21,7 @@
     "build:esm": "cross-env BABEL_ENV=esm yarn build:babel -d esm src",
     "build:misc": "lerna exec -- cp ../../LICENSE ../../NOTICE .",
     "clean": "lerna exec -- rimraf LICENSE NOTICE esm lib",
-    "lint": "eslint .",
+    "lint": "eslint --ext js,ts .",
     "prepare": "lerna run prepare",
     "prepublishOnly": "yarn run build",
     "start": "yarn run web:server",
@@ -42,8 +42,9 @@
     "@types/mocha": "^7.0.2",
     "@types/node-fetch": "^2.5.7",
     "@types/resolve": "^1.17.0",
+    "@typescript-eslint/eslint-plugin": "^3.7.0",
+    "@typescript-eslint/parser": "^3.7.0",
     "ajv": "^6.11.0",
-    "babel-eslint": "^10.0.3",
     "babel-loader": "^8.0.5",
     "babel-plugin-istanbul": "^6.0.0",
     "babel-plugin-module-resolver": "^4.0.0",