Restoring Order to My Typescript, Meteor, React Dev Environment

I find myself with 3 places in which Typescript & typescript-eslint errors are reported, and they are disagreeing with each other.

  1. $ meteor
  2. $ meteor npx eslint . --ext .js,.jsx,.ts,.tsx
  3. TypeScript Plugin for Sublime Text
    • Side note/question: This plugin required me to install a system-level node because the settings aren’t flexible enough to point it to meteor node, but I suppose some sort of script in my path that forwards arguments may be possible. This has me wondering whether most meteor developers also install node at the system level to make 3rd party packages happy?
    • Also, I can’t use absolute path imports without this plugin complaining even though they end up compiling without a hitch.

I would ideally like to have a dev setup where Typescript errors and eslint errors (for .js, .jsx, .ts, .tsx since tslint is going away), are all following the same .eslintrc and tsconfig.json such that the errors emitted when running $ meteor or $ meteor npx eslint and viewing code in my editor present a unified front. Is such a thing possible? I’m not fixed on using SublimeText, just used to it.

I’m using https://atmospherejs.com/barbatus/typescript and a handful of other packages related to typescript-eslint.

I’m a newcomer to Meteor, so my efforts to get a Typescript/React/Meteor dev environment up and running with eslint and SublimeText have mainly been trying to stitch together various guides on some subset of these tools. The result is that my configuration has ended up a bit of a mess. I’m hoping someone with more experience can help me get a more reasonable dev setup. Thanks!

packages.json:

{
  "name": "derp",
  "private": true,
  "scripts": {
    "lint": "eslint_d . --ext .js,.ts,.jsx,.tsx",
    "pretest": "npm run lint --silent",
    "start": "meteor run",
    "test": "meteor test --once --driver-package meteortesting:mocha",
    "test-app": "TEST_WATCH=1 meteor test --full-app --driver-package meteortesting:mocha",
    "visualize": "meteor --production --extra-packages bundle-visualizer"
  },
  "dependencies": {
    "@babel/runtime": "^7.3.4",
    "@types/react": "^16.8.22",
    "@types/semantic-ui": "^2.2.7",
    "meteor-node-stubs": "^0.4.1",
    "react": "^16.5.0",
    "react-dom": "^16.5.0",
    "react-router-dom": "^5.0.1",
    "semantic-ui-react": "^0.87.1",
    "typescript": "^3.5.2",
    "underscore": "^1.9.1"
  },
  "meteor": {
    "mainModule": {
      "client": "client/main.tsx",
      "server": "server/main.ts"
    },
    "testModule": "tests/main.js"
  },
  "devDependencies": {
    "@meteorjs/eslint-config-meteor": "^1.0.5",
    "@types/meteor": "^1.4.28",
    "@types/node": "^12.0.10",
    "@types/react-dom": "^16.8.4",
    "@types/react-router-dom": "^4.3.4",
    "@typescript-eslint/eslint-plugin": "^1.11.0",
    "@typescript-eslint/parser": "^1.11.0",
    "babel-eslint": "^10.0.1",
    "eslint": "^5.16.0",
    "eslint-config-airbnb": "^17.1.0",
    "eslint-import-resolver-meteor": "^0.4.0",
    "eslint-plugin-import": "^2.17.3",
    "eslint-plugin-jsx-a11y": "^6.2.1",
    "eslint-plugin-meteor": "^5.1.0",
    "eslint-plugin-react": "^7.14.2",
    "eslint-plugin-react-hooks": "^1.6.0",
    "eslint_d": "^7.3.0"
  }
}

.eslintrc

{
  "parser": "@typescript-eslint/parser",
  "parserOptions": {
    "ecmaVersion": 6,
    "sourceType": "module",
    "ecmaFeatures": {
      "jsx": true
    },
    "project": "./tsconfig.json"
  },
  "env": {
    "es6": true,
    "browser": true,
    "node": true,
    "meteor": true
  },
  "plugins": [
    "meteor",
    "react",
    "@typescript-eslint"
  ],
  "extends": [
    "airbnb/base",
    "eslint:recommended",
    "plugin:meteor/recommended",
    "plugin:react/recommended",
    "plugin:@typescript-eslint/recommended"
  ],
  "globals": {
    "Links": "writable"
  },
  "settings": {
    "import/resolver": {
      "meteor": {
        "extensions": [".js", ".jsx", ".ts", ".tsx"]
      }
    },
    "react": {
      "version": "detect"
    }
  },
  "rules": {
    "indent": "off",
    "@typescript-eslint/indent": ["error", 2],
    "@typescript-eslint/explicit-function-return-type": ["error", {
        "allowExpressions": true,
        "allowTypedFunctionExpressions": true
    }],
    "@typescript-eslint/prefer-interface": "off",
    "@typescript-eslint/consistent-type-definitions": ["error", "type"],
    "import/prefer-default-export": "off",
    "quotes": [
        "error",
        "single",
        // To allow Template Literals inside Component props.
        // ex. <Component width={`50%`}/>
        //
        { "allowTemplateLiterals": true }
    ],
    // To allow absolute path imports in Meteor
    "import/no-absolute-path": [
      "off"
    ],
    // To resolve https://github.com/clayne11/eslint-import-resolver-meteor/issues/17
    "import/extensions": [
      "off",
      "never"
    ],
    // Work around until  https://github.com/benmosher/eslint-plugin-import/issues/479 is resolved
    "import/no-extraneous-dependencies": [
      "off"
    ],
    // To allow `_id` access when retrieving Mongo documents
    "no-underscore-dangle": [
      "off"
    ]
  }
}

tsconfig.json:

{
  "compilerOptions": {
    "outDir": "build/dist",
    "module": "commonjs",
    "target": "es5",
    "lib": ["es6", "dom"],
    "sourceMap": true,
    "allowJs": true,
    "jsx": "react",
    "allowSyntheticDefaultImports": false,
    "baseUrl": ".",
    "moduleResolution": "node",
    "noImplicitReturns": true,
    "noImplicitThis": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "typeRoots": ["node_modules/@types"]
  },
  "exclude": [
    "node_modules"
  ]
}

You probably want to follow this thread as it has a wealth of info on using TypeScript with meteor:

And also checkout the newer Typescript package for Meteor adornis:typescript

Not using TypeScript personally at the moment because I have some migration to do first from Flow but I hope this helps you. Hopefully some others will chime in as well!

2 Likes

Thanks @hexsprite! That thread was super useful.

Btw, for future readers, most of my problems just disappeared by just switching from sublime to vscode.