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
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
- Claim a package in this issue
- Copy
tsconfig.json from an already migrated package
- If the package you're migrating have dependencies on another package in this repo, use
references
- 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
- Add
"types": "build/index.d.ts" to package.json below main
- Rename all files with
js extension to ts (or tsx if they have jsx in them), fixing type errors as you go
- Make sure tests and lint (including flow) pass
- Ensure that the JS after compilation is essentially the same as before migrating*
- 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)
- run
yarn build on master
git add -f packages/MY_PACKAGE/build*
git commit -m 'before migration'
- run
yarn build on your branch with the migration
rm packages/MY_PACKAGE/build*/**/*.ts packages/MY_PACKAGE/build*/**/*.map
git add -f packages/MY_PACKAGE/build*
git commit -m 'after migration'
git diff master packages/MY_PACKAGE/build*
- 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.
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
@jest/core@jest/reporters@jest/transformbabel-jestbabel-plugin-jest-hoistbabel-preset-jestdiff-sequenceseslint-config-fb-strictexpectjestjest-changed-filesjest-circusjest-clijest-configjest-diffjest-docblockjest-eachjest-environment-jsdomjest-environment-nodejest-get-typejest-haste-mapjest-jasmine2jest-leak-detectorjest-matcher-utilsjest-message-utiljest-mockjest-phabricatorjest-regex-utiljest-repljest-resolvejest-resolve-dependenciesjest-runnerjest-runtimejest-serializerjest-snapshotjest-utiljest-validatejest-watcherjest-workerpretty-formatAfter 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-cliwill 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
tsconfig.jsonfrom an already migrated packagereferencestypes/in the root of the repo for the package, move that into the package'ssrcdirectory as a file namedtypes.ts"types": "build/index.d.ts"to package.json belowmainjsextension tots(ortsxif they have jsx in them), fixing type errors as you goTo build, you can run
yarn buildoryarn watchin the root of the repository.You can look at my PR for
pretty-formatfor a look at how a migration might look.You can use
flow-to-typescriptto help in migration. However, since the syntax between Flow and Typescript is so similar, I personally only used it for the type definition files intypes- for normal source files it was easier to rename the file tots(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)yarn buildonmastergit add -f packages/MY_PACKAGE/build*git commit -m 'before migration'yarn buildon your branch with the migrationrm packages/MY_PACKAGE/build*/**/*.ts packages/MY_PACKAGE/build*/**/*.mapgit add -f packages/MY_PACKAGE/build*git commit -m 'after migration'git diff master packages/MY_PACKAGE/build*git --no-pager diff master packages/MY_PACKAGE/build* | pbcopy. Stick that in a code fence withdiffsyntax in the PR.Things to look out for during migration
The config doesn't allow implicit
anyOut 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 useunknowninstead ofany.The module exports CommonJS
Convert
requiretoimportUseexports =to replacemodules.exports- this allows TypeScript to understand the export. We include a babel-plugin which transpiles this intomodule.exportsfor the distributed code (and tests).Potential gotchas
Probably more, but I'll write down the ones I know of
types/in the root of this repo, allowing us to use types across packages without dependencies on them (typically modules will depend ontypes/Configwhich allow them to haveProjectConfigas arguments). Since we'll be distributing the types, we need those dependencies to be explicit.jest-confighas today except for the default configs (so it can dropbabel-jest, the test environments etc)types/TestResultis used byjest-jasmine2,jest-circusandjest-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-typesproject that's just types that are shared between modules.Ideas here are very much welcome!
EDIT: As of #7834, I've created a
@jest/typespackagePS: 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/jestalready. 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.