mirror of
				https://github.com/zulip/zulip.git
				synced 2025-11-03 21:43:21 +00:00 
			
		
		
		
	docs: Add initial documentation for TypeScript.
This is a draft/preliminary document on how we're doing our TypeScript migration; I'm sure we'll add a lot more over the coming weeks.
This commit is contained in:
		@@ -11,5 +11,6 @@ Code Testing
 | 
			
		||||
   testing-with-node
 | 
			
		||||
   testing-with-casper
 | 
			
		||||
   mypy
 | 
			
		||||
   typescript
 | 
			
		||||
   continuous-integration
 | 
			
		||||
   manual-testing
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										103
									
								
								docs/testing/typescript.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								docs/testing/typescript.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,103 @@
 | 
			
		||||
# TypeScript static types
 | 
			
		||||
 | 
			
		||||
Zulip is early in the process of migrating our codebase to use
 | 
			
		||||
[TypeScript](https://www.typescriptlang.org/), the leading static type
 | 
			
		||||
system for JavaScript.  It works as an extension of the ES6 JavaScript
 | 
			
		||||
standard, and provides similar benefits to our use of
 | 
			
		||||
[the mypy static type system for Python](../testing/mypy.html).
 | 
			
		||||
 | 
			
		||||
We expect to eventually migrate the entire JavaScript codebase to
 | 
			
		||||
TypeScript, though our current focus is on getting the tooling and
 | 
			
		||||
migration process right, not on actually migrating the codebase.
 | 
			
		||||
 | 
			
		||||
As a result, the details in this document are preliminary ideas for
 | 
			
		||||
discussion and very much subject to change.
 | 
			
		||||
 | 
			
		||||
A typical piece of TypeScript code looks like this:
 | 
			
		||||
 | 
			
		||||
``` ts
 | 
			
		||||
setdefault(key: K, value: V): V {
 | 
			
		||||
    const mapping = this._items[this._munge(key)];
 | 
			
		||||
    if (mapping === undefined) {
 | 
			
		||||
        return this.set(key, value);
 | 
			
		||||
    }
 | 
			
		||||
    return mapping.v;
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The following resources are valuable for learning TypeScript:
 | 
			
		||||
 | 
			
		||||
* The main documentation on [TypeScript syntax][typescript-handbook].
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## Type checking
 | 
			
		||||
 | 
			
		||||
TypeScript types are checked primarily via `webpack`, so you'll see
 | 
			
		||||
typing errors in red in your `run-dev.py` console as you do
 | 
			
		||||
development.
 | 
			
		||||
 | 
			
		||||
TODO: Document command for running the type check manually.
 | 
			
		||||
 | 
			
		||||
## Linting and style
 | 
			
		||||
 | 
			
		||||
We use the Eslint plugin for TypeScript to lint TypeScript code, just
 | 
			
		||||
like we do for JavaScript.  Our long-term goal is to use an idiomatic
 | 
			
		||||
TypeScript style for our TypeScript codebase.
 | 
			
		||||
 | 
			
		||||
However, because we are migrating an established JavaScript codebase,
 | 
			
		||||
we plan to start with a style that is closer to the existing
 | 
			
		||||
JavaScript code, so that we can easily migrate individual modules
 | 
			
		||||
without too much code churn.  A few examples:
 | 
			
		||||
 | 
			
		||||
* TypeScript generally prefers explicit `return undefined;`, whereas
 | 
			
		||||
  our existing JavasScript style uses just `return;`.
 | 
			
		||||
* With TypeScript, we expect to make heavy use of `let` and `const`
 | 
			
		||||
  rather than `var`.
 | 
			
		||||
* With TypeScript/ES6, we may no longer need to use `_.each()` as our
 | 
			
		||||
  recommended way to do loop iteration.
 | 
			
		||||
 | 
			
		||||
For each of the details, we will either want to bulk-migrate the
 | 
			
		||||
existing JavaScript codebase before the migration or plan to do it
 | 
			
		||||
after JS->TS migration for a given file, so that we don't need to
 | 
			
		||||
modify these details as part of converting a file from JavaScript to
 | 
			
		||||
TypeScript.
 | 
			
		||||
 | 
			
		||||
A possibly useful technique for this will be setting some eslint
 | 
			
		||||
override rules at the top of individual files in the first commit that
 | 
			
		||||
converts them from JS to TS.
 | 
			
		||||
 | 
			
		||||
## Migration strategy
 | 
			
		||||
 | 
			
		||||
Our plan is to order which modules we migrate carefully, starting with
 | 
			
		||||
those that:
 | 
			
		||||
 | 
			
		||||
* Appear frequently as reverse dependencies of other modules
 | 
			
		||||
  (e.g. `people.js`).  These are most valuable to do first because
 | 
			
		||||
  then we have types on the data being interacted with by other
 | 
			
		||||
  modules when we migrate those.
 | 
			
		||||
* Don't have large open pull requests (to avoid merge conflicts); one
 | 
			
		||||
  can scan for these using [TinglingGit](https://github.com/zulip/TinglingGit).
 | 
			
		||||
* Have good unit test coverage, which limits the risk of breaking
 | 
			
		||||
  correctness through refactoring.  Use `tools/test-js-with-node
 | 
			
		||||
  --coverage` to get a coverage report.
 | 
			
		||||
 | 
			
		||||
When migrating a module, we want to be especially thoughtful about
 | 
			
		||||
putting together a commit structure that makes mistakes unlikely and
 | 
			
		||||
the changes easy to verify.  E.g.:
 | 
			
		||||
 | 
			
		||||
* First a commit that just converts the language to TypeScript adding
 | 
			
		||||
  types.  The result may potentially have some violations of the
 | 
			
		||||
  long-term style we want (e.g. not using `const`).  Depending on how
 | 
			
		||||
  we're handling linting, we set some override eslint rules at the top
 | 
			
		||||
  of the module at this stage so CI still passes.
 | 
			
		||||
* Then a commit just migrating use of `var` to `const/let` without
 | 
			
		||||
  other changes (other than removing any relevant linter overrides).
 | 
			
		||||
* Etc.
 | 
			
		||||
 | 
			
		||||
With this approach, we should be able to produce a bunch of really
 | 
			
		||||
simple commits that can be merged the same day they're written without
 | 
			
		||||
significant risk of introducing regressions from typos, refactors that
 | 
			
		||||
don't quite work how they were expected to, etc.
 | 
			
		||||
 | 
			
		||||
[typescript-handbook]: https://www.typescriptlang.org/docs/handbook/basic-types.html
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user