Main resource: https://basarat.gitbook.io/typescript/
- Typescript is a superset of Javascript. The type system in Typescript is designed to be optional so that your Javascript is Typescript. It does not block Javascript emit in the presence of type errors, allowing users to progressively update JS to TS.
- Upgrading to TS without anyone noticing: https://devblogs.microsoft.com/typescript/how-to-upgrade-to-typescript-without-anybody-noticing-part-1/
- Migrating JS -> TS
- Add a
tsconfig.json. - Convert files from
.jsto.ts. Suppress errors usingany. - Write new code in TS avoiding using
any. - Go back to old code and start adding type annotations and fixing bugs.
- Use ambient definitions for third party JS code.
- Add a
- Make use of
readonlyandReadonly,ReadonlyArrayetc features. -
I find it simplest to always be explicit about function returns. After all, these annotations are a theorem and the function body is the proof.
- You can use any prefix for generics, but it's common to use
T, based on templates inC. - Use ambient definitions in declaration files
*.d.tsto suppress typescript errors in third party code. This can also be used for non-JS imports e.g.declare module "*.css" lib.d.tsincludes declarations for most core JS interfaces and variables. You can edit this incompilerOptionsand supply additional libs (e.g.dom,es6).- DO NOT throw raw strings for errors. They become difficult to debug, always try to use the right errors. In fact, it's better to pass the
errorobject itself around with callback (nodedoes this). - If a file has the extension
.d.ts, then each root level definition must have thedeclarekeyword prefixed to it. Use aninterfacewhenever possible instead of simply declaringany. - Use
module: commonJsintsconfig.json - Study
Promise. - Study
async/awaitand understand how they use generators (function*) under the hood. - Typescript has concept of "type declaration space" (
interface,class,type) and "variable declaration space" (class,var,let,constetc). - Modules are looked up in order of
foo.js,foo/index.js,foo/package.json(mainortypesfield). - If we declare a module globally in
global.d.ts, they will appear magically to that path. Prefer file-based modules for this though. - Recommended style guide: https://basarat.gitbook.io/typescript/styleguide
- Don't prefix interfaces with
I* - Use
PascalCaseforEnum,Class,InterfaceandcamelCasefor everything else. - Name files with
camelCase. - Prefer
[]instead ofArray<>syntax for arrays.
- Don't prefix interfaces with
- If we need to emit JS, make sure the imported variables/types are actually used in code.
- Avoid circular dependencies.
- Avoid type assertions.
- Avoid
namespace. Use external modules instead. enumsare numeric by nature. They are self-incrementing, so make use of number enums as flags (i.e. assignNoneenum key to the first entry so you can use it for falsy checks!): https://basarat.gitbook.io/typescript/type-system/enums#number-enums-as-flags- Use
interfaceif you have types with hierarchies, allowing access toimplementsandextends. Use type alias (i.e.type Foo = string | Barto provide semantic names, allowing easy setup with unions or intersections. - Explore dynamic import expressions in various projects.
npm installandyarn addonly installs non-dev dependencies. If using@types/*modules, install these asdevDependencies.- Avoid
export default: poor discoverability, error-prone refactors, cumbersome re-export syntax. - Turn on
noImplicitAnyandstrictNullChecks. - Use the
!non-null assertion + definite assignment assertion operators in applicable places. - Use
barrels(i.e. re-exporting interfaces into a commonMyModule/index.js). You can collect named exports into a variable and export that variable to expose the object of methods instead: https://basarat.gitbook.io/typescript/main-1/barrel - Authoring typescript libraries: https://basarat.gitbook.io/typescript/library
jesthas good typescript support: https://basarat.gitbook.io/typescript/intro-1/jest. Run it in--watchmode.- Mapped types are useful. You can also use
keyofandtypeofvocabulary terms.type Index = 'a' | 'b' | 'c'; type FromIndex = { [k in Index]?: number } const colors = { red: 'reddish', blue: 'bluish', }; type Colors = keyof typeof colors; let color: Colors; - React types in detail: https://basarat.gitbook.io/typescript/tsx/react
ReactNodeconsolidatesJSXandstring.- You can specify the type to
React.ReactElement<T>(e.g.React.ReactElement<MyAwesomeComponent>inclass MyAwesomeComponent extends React.Component) - Redux typescript in a nutshell: https://basarat.gitbook.io/typescript/type-system/discriminated-unions#redux
- At any time we do not have typescript types, we can declare these globally in the respective namespace for Typescript to pick up:
declare global {
namespace JSX {
interface IntrinsicElements {
'my-awesome-slider': MyAwesomeSliderProps;
}
interface MyAwesomeSliderProps extends React.Attributes {
name: string;
}
}
}- Briefly how typescript works:
SourceCode ~~ scanner ~~> Token Stream ~~ parser ~~> AST ~~ binder ~~> SymbolsAST + Symbols ~~ checker ~~> Type ValidationAST + Checker ~~ emitter ~~> JS