-
Notifications
You must be signed in to change notification settings - Fork 66
TypeScript file conversion steps
We aim to gradually migrate this project from JavaScript to TypeScript.
-
Rename the JavaScript file extension to
.tsand commit your change. It's important that the.jsfile is removed from git before the next step. -
Run
yarn compileoryarn compile --watch. You should see the built files (.js,.d.ts, and.js.map) created in the file tree. Do not commit them. -
Add the built filenames explicitly to the top-level
.gitignorefile. This step will only work if the old.jsfile was already removed in a git commit, because.gitignoredoesn't apply to files that are already being tracked.Any gitignored files will also not be checked by eslint, which is what you want (they are compiled output, not code you authored).
If you skip over any types that should be declared in later refactors, import the todo-any type from @cardstack/plugin-utils/todo-any and use it instead of any. This way, we can easily search for places to update as we change more files into TypeScript. Save any for things that are fine to stay un-typed. Example:
import { todo } from '@cardstack/plugin-utils/todo-any';
interface PrivateOperations {
sourceId: string;
// this is an instance of the SourcesUpdate class,
// which hasn't been converted to TypeScript yet
sourcesUpdate: todo;
nonce: Number | null;
}If you're typing a variable that holds a JSON:API document (or part of one), you should use the types from jsonapi-typescript.
It's ideal to author TypeScript using ES Modules, as opposed to CommonJS. But TypeScript also has a special syntax for CommonJS compatibility, and you may need it as we do our incremental conversion.
When importing things (both TS and unconverted JS) into your newly-converted TypeScript file, it's safe to use normal ES module import syntax (because we use the esModuleInterop setting in tsconfig.json):
// the default export works
-const fs = require('fs');
+import fs from 'fs';
// as do named exports
- const { writeFileSync } = require('fs');
+ import { writeFileSync } from 'fs';When exporting things out of your newly-converted TypeScriptFile, you may need to maintain compatibility with existing Javascript files that consume your module via require. There are three main possibilities:
-
Your original file used only named exports, that people consume via
require('./your-module').someName. In this case, you can directly convert to named ES module exports:-exports.someUtility = function someUtility() {}; +export function someUtility() {}
-
Your original file replaced the entire
exportsobject and your only consumers have already been converted to TypeScript. In this case, you can directly convert to a default ES module export:-module.exports = SomeThing; +export default SomeThing;
-
Your original file replaced the entire
exportsobject and you have existing Javascript consumers that userequire('your-module). In this case, you need the special compatibility syntax:-module.exports = SomeThing; +export = SomeThing;
The point of this syntax is to allow Javascript consumers to keep saying
require('./your-module')rather thanrequire('./your-module').default.
When in doubt between 2 and 3, it's safe to always pick 3. We can always come back later once everything is TS and update them all to 2.
We have a type definition for the global expect that we use in node-tests, but it doesn't yet include the extensions added by prepare-node-tests.js. Once those are needed, we should port prepare-node-tests.js itself to TS, and use that resulting type in types/cardstack__test-support/index.d.ts.