Skip to content

☂️TypeScript migration tracking issue #7807

Closed
@SimenB

Description

@SimenB

This issue is meant to track Jest's internal migration to TypeScript.

Process

We would love to get help from the community here. I've compiled a list of all the packages in this repo below - feel free to claim any package not claimed and submit a PR migrating it.

List

Package Name Task Owner PR Status Notes
@jest/core @SimenB #7998 MERGED
@jest/reporters @loryman #7994 MERGED
@jest/transform @SimenB #7918 MERGED
babel-jest @SimenB #7862 MERGED
babel-plugin-jest-hoist @deneuv34 #7898 MERGED
babel-preset-jest - - - Not transpiled
diff-sequences @loryman #7820 MERGED
eslint-config-fb-strict - - - Not transpiled
expect @natealcedo #7919 MERGED
jest @SimenB #8024 MERGED
jest-changed-files @loryman #7827 MERGED
jest-circus @doniyor2109 #7916 MERGED
jest-cli @SimenB #8024 MERGED
jest-config @SimenB #7944 MERGED
jest-diff @SimenB #7824 MERGED
jest-docblock @SimenB #7836 MERGED
jest-each @mattphillips #8007 MERGED
jest-environment-jsdom @lirbank #8003 MERGED
jest-environment-node @lirbank #7985 MERGED
jest-get-type @SimenB #7818 MERGED
jest-haste-map @jeysal #7854 MERGED
jest-jasmine2 @doniyor2109 #7970 MERGED
jest-leak-detector @r3nya #7825 MERGED
jest-matcher-utils @SimenB #7835 MERGED
jest-message-util @SimenB #7834 MERGED
jest-mock @thymikee #7847 MERGED
jest-phabricator @r3nya #7965 MERGED
jest-regex-util @loryman #7822 MERGED
jest-repl @natealcedo #8000 MERGED
jest-resolve @SimenB #7871 MERGED
jest-resolve-dependencies @jeysal #7922 MERGED
jest-runner @natealcedo #7968 MERGED
jest-runtime @SimenB #7964 MERGED
jest-serializer @thymikee #7841 MERGED
jest-snapshot @doniyor2109 #7899 MERGED
jest-util @SimenB #7844 MERGED
jest-validate @SimenB #7991 MERGED
jest-watcher @SimenB #7843 MERGED
jest-worker @SimenB #7853 MERGED
pretty-format @SimenB #7809 MERGED

After all packages are migrated, we can start to migrate our integration tests. Depending on how this migration goes, we can track that in this issue as well, or we can track it separately later.

How

Order of packages to migrate

One thing to note is that because this repo is a monorepo, we have dependencies between packages. So we have to migrate leaf packages (without dependencies) first, then walk up the dependency tree until everything is migrated. Which means jest-cli will be the last package migrated.

You can use yarn to figure out which packages depend on which internally: yarn --silent workspaces info. This will output a JSON object of all packages in the workspace. An example looks like this:

{
  "babel-jest": {
    "location": "packages/babel-jest",
    "workspaceDependencies": ["babel-preset-jest"],
    "mismatchedWorkspaceDependencies": []
  }
}

The interesting part here is workspaceDependencies. If that array is empty, that's a perfect package to start migrating. If it is not empty, you'll want to make sure that every package listed in the array has been migrated already.

Steps

  1. Claim a package in this issue
  2. Copy tsconfig.json from an already migrated package
    1. If the package you're migrating have dependencies on another package in this repo, use references
  3. If a type file exists in types/ in the root of the repo for the package, move that into the package's src directory as a file named types.ts
  4. Add "types": "build/index.d.ts" to package.json below main
  5. Rename all files with js extension to ts (or tsx if they have jsx in them), fixing type errors as you go
  6. Make sure tests and lint (including flow) pass
  7. Ensure that the JS after compilation is essentially the same as before migrating*
  8. Open up a PR

To build, you can run yarn build or yarn watch in the root of the repository.

You can look at my PR for pretty-format for a look at how a migration might look.

You can use flow-to-typescript to help in migration. However, since the syntax between Flow and Typescript is so similar, I personally only used it for the type definition files in types - for normal source files it was easier to rename the file to ts(x) and fix the syntax errors that my IDE showed me.

*) Do this by comparing git diffs before and after migration (also please include this diff in the PR after opening it)

  1. run yarn build on master
  2. git add -f packages/MY_PACKAGE/build*
  3. git commit -m 'before migration'
  4. run yarn build on your branch with the migration
  5. rm packages/MY_PACKAGE/build*/**/*.ts packages/MY_PACKAGE/build*/**/*.map
  6. git add -f packages/MY_PACKAGE/build*
  7. git commit -m 'after migration'
  8. git diff master packages/MY_PACKAGE/build*
  9. On macOS (there probably exists similar tools on Linux and Windows), this can be copied and included in the PR git --no-pager diff master packages/MY_PACKAGE/build* | pbcopy. Stick that in a code fence with diff syntax in the PR.

Things to look out for during migration

The config doesn't allow implicit any

Out current setup with flow allows this - just add an explicit any (or a stricter type if you're able) in those cases. If possible, please use unknown instead of any.

The module exports CommonJS

Convert require to import Use exports = to replace modules.exports - this allows TypeScript to understand the export. We include a babel-plugin which transpiles this into module.exports for the distributed code (and tests).

Potential gotchas

Probably more, but I'll write down the ones I know of

  • Jest currently imports quite a lot of types from types/ in the root of this repo, allowing us to use types across packages without dependencies on them (typically modules will depend on types/Config which allow them to have ProjectConfig as arguments). Since we'll be distributing the types, we need those dependencies to be explicit.
    • A solution in this concrete case is probably to create a separate packages that has everything jest-config has today except for the default configs (so it can drop babel-jest, the test environments etc)
  • Similarly, types/TestResult is used by jest-jasmine2, jest-circus and jest-cli (for reporters). We need to figure out how to share that type effectively between packages.

Another idea on how to solve "type sharing" is to use a separate jest-types project that's just types that are shared between modules.

Ideas here are very much welcome!

EDIT: As of #7834, I've created a @jest/types package


PS: This will not affect anyone using Jest (unless you use the modules exported by Jest directly, which will become typed). This is strictly an internal refactor. We will not be considering adding types to be a breaking change.

PPS: It is currently a non-goal to distribute TS types for using Jest - that is excellently handled in @types/jest already. At some point we might want to distribute that with jest as well - but that's a separate issue.

PPPS: This issue is not for discussions about the merits of the migration in and of itself - that feedback can be posted in the RFC. However, if you have experience migrating, building, testing or distributing a module written in TS, feel free to chime in with learnings from that process in this issue.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions