├── .gitignore
├── CODE_OF_CONDUCT.md
├── GLOSSARY.md
├── LICENSE
├── LICENSE-CODE
├── README.md
├── SECURITY.md
├── codebase
├── screenshots
│ ├── snippet-vscode.png
│ └── threeslash-refs.png
└── src
│ ├── compiler
│ ├── binder.md
│ ├── checker-inference.md
│ ├── checker-relations.md
│ ├── checker-widening-narrowing.md
│ ├── checker.md
│ ├── emitter.md
│ ├── faq.md
│ ├── parser.md
│ ├── scanner.md
│ ├── services.md
│ ├── types.md
│ └── utils.md
│ └── services
│ ├── completions.md
│ └── textChanges.md
├── intro
├── README.md
└── imgs
│ ├── compiler-linear.png
│ └── layers-2.png
├── package.json
├── scripts
└── updateFindLinks.js
└── systems
├── cli.md
├── codefixes.md
├── debugging
├── printing.md
└── settings.md
├── formatting
└── formatting.md
├── refactor.md
├── sourcemaps.md
├── testing
├── README.md
├── baselines.md
├── fourslash.md
├── screenshots
│ └── diff.png
└── units.md
└── vscode
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | lerna-debug.log*
8 |
9 | # Diagnostic reports (https://nodejs.org/api/report.html)
10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
11 |
12 | # Runtime data
13 | pids
14 | *.pid
15 | *.seed
16 | *.pid.lock
17 |
18 | # Directory for instrumented libs generated by jscoverage/JSCover
19 | lib-cov
20 |
21 | # Coverage directory used by tools like istanbul
22 | coverage
23 | *.lcov
24 |
25 | # nyc test coverage
26 | .nyc_output
27 |
28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
29 | .grunt
30 |
31 | # Bower dependency directory (https://bower.io/)
32 | bower_components
33 |
34 | # node-waf configuration
35 | .lock-wscript
36 |
37 | # Compiled binary addons (https://nodejs.org/api/addons.html)
38 | build/Release
39 |
40 | # Dependency directories
41 | node_modules/
42 | jspm_packages/
43 |
44 | # TypeScript v1 declaration files
45 | typings/
46 |
47 | # TypeScript cache
48 | *.tsbuildinfo
49 |
50 | # Optional npm cache directory
51 | .npm
52 |
53 | # Optional eslint cache
54 | .eslintcache
55 |
56 | # Microbundle cache
57 | .rpt2_cache/
58 | .rts2_cache_cjs/
59 | .rts2_cache_es/
60 | .rts2_cache_umd/
61 |
62 | # Optional REPL history
63 | .node_repl_history
64 |
65 | # Output of 'npm pack'
66 | *.tgz
67 |
68 | # Yarn Integrity file
69 | .yarn-integrity
70 |
71 | # dotenv environment variables file
72 | .env
73 | .env.test
74 |
75 | # parcel-bundler cache (https://parceljs.org/)
76 | .cache
77 |
78 | # Next.js build output
79 | .next
80 |
81 | # Nuxt.js build / generate output
82 | .nuxt
83 | dist
84 |
85 | # Gatsby files
86 | .cache/
87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js
88 | # https://nextjs.org/blog/next-9-1#public-directory-support
89 | # public
90 |
91 | # vuepress build output
92 | .vuepress/dist
93 |
94 | # Serverless directories
95 | .serverless/
96 |
97 | # FuseBox cache
98 | .fusebox/
99 |
100 | # DynamoDB Local files
101 | .dynamodb/
102 |
103 | # TernJS port file
104 | .tern-port
105 | .DS_Store
106 |
107 | yarn.lock
108 | package-lock.json
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Microsoft Open Source Code of Conduct
2 |
3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
4 |
5 | Resources:
6 |
7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/)
8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/)
9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns
10 |
--------------------------------------------------------------------------------
/GLOSSARY.md:
--------------------------------------------------------------------------------
1 | ### Terminology from inside the codebase
2 |
3 | - **Core TypeScript Compiler**
4 |
5 | - **Parser:** Starting from a set of sources, and following the productions of the language grammar, to generate an Abstract Syntax Tree (AST). [See Parser](https://basarat.gitbook.io/typescript/overview/parser)
6 |
7 | - **Binder:** Linking declarations contributing to the same structure using a Symbol (e.g. different declarations of the same interface or module, or a function and a module with the same name). This allows the type system to reason about these named declarations. [See Binder](https://basarat.gitbook.io/typescript/overview/binder)
8 | - **Type resolver/ Checker:** Resolving types of each construct, checking semantic operations and generate diagnostics as appropriate. [See Checker](https://basarat.gitbook.io/typescript/overview/checker)
9 |
10 | - **Emitter:** Output generated from a set of inputs (.ts and .d.ts) files can be one of: JavaScript (.js), definitions (.d.ts), or source maps (.js.map)
11 |
12 | - **Pre-processor:** The "Compilation Context" refers to all files involved in a "program". The context is created by inspecting all files passed in to the compiler on the command line, in order, and then adding any files they may reference directly or indirectly through `import` statements and `/// ` tags.
13 | The result of walking the reference graph is an ordered list of source files, that constitute the program.
14 | When resolving imports, preference is given to ".ts" files over ".d.ts" files to ensure the most up-to-date files are processed.
15 | The compiler does a node-like process to resolve imports by walking up the directory chain to find a source file with a .ts or .d.ts extension matching the requested import.
16 | Failed import resolution does not result in an error, as an ambient module could be already declared.
17 |
18 | - **Standalone compiler (tsc):** The batch compilation CLI. Mainly handle reading and writing files for different supported engines (e.g. Node.js)
19 |
20 | - **Language Service:** The "Language Service" exposes an additional layer around the core compiler pipeline that are best suiting editor-like applications.
21 | The language service supports the common set of a typical editor operations like statement completions, signature help, code formatting and outlining, colorization, etc... Basic re-factoring like rename, Debugging interface helpers like validating breakpoints as well as TypeScript-specific features like support of incremental compilation (--watch equivalent on the command-line). The language service is designed to efficiently handle scenarios with files changing over time within a long-lived compilation context; in that sense, the language service provides a slightly different perspective about working with programs and source files from that of the other compiler interfaces.
22 |
23 | > Please refer to the [[Using the Language Service API]] page for more details.
24 |
25 | - **Standalone Server (tsserver):** The `tsserver` wraps the compiler and services layer, and exposes them through a JSON protocol.
26 | > Please refer to the [[Standalone Server (tsserver)]] for more details.
27 |
28 | ### Type stuff which can be see outside the compilers
29 |
30 | - Node: The basic building block of the Abstract Syntax Tree (AST). In general node represent non-terminals in the language grammar; some terminals are kept in the tree such as identifiers and literals.
31 |
32 | - SourceFile: The AST of a given source file. A SourceFile is itself a Node; it provides an additional set of interfaces to access the raw text of the file, references in the file, the list of identifiers in the file, and mapping from a position in the file to a line and character numbers.
33 |
34 | - Program: A collection of SourceFiles and a set of compilation options that represent a compilation unit. The program is the main entry point to the type system and code generation.
35 |
36 | - Symbol: A named declaration. Symbols are created as a result of binding. Symbols connect declaration nodes in the tree to other declarations contributing to the same entity. Symbols are the basic building block of the semantic system.
37 |
38 | - `Type`: Types are the other part of the semantic system. Types can be named (e.g. classes and interfaces), or anonymous (e.g. object types).
39 |
40 | - Signature``: There are three types of signatures in the language: call, construct and index signatures.
41 |
42 | * `Transient Symbol` - A symbol created in the checker, as opposed to in the binder
43 | * `Freshness` - When a literal type is first created and not expanded by hitting a mutable location, see [Widening
44 | and Narrowing in TypeScript][wnn].
45 |
46 | * `Expando` - This is [the term](https://developer.mozilla.org/en-US/docs/Glossary/Expando) used to describe taking a JS object and adding new things to it which expands the type's shape
47 |
48 | ```js
49 | function doSomething() {}
50 | doSomething.doSomethingElse = () => {};
51 | ```
52 |
53 | In TS, this is only allowed for adding properties to functions. In JS, this is a normal pattern in old school code for all kinds of objects. TypeScript will augment the types for `doSomething` to add `doSomethingElse` in the type system in both.
54 |
55 | * `Structural Type System` - A school of types system where the way types are compared is via the structure of
56 | their properties.
57 |
58 | For example:
59 |
60 | ```ts
61 | interface Duck {
62 | hasBeak: boolean;
63 | flap: () => void;
64 | }
65 |
66 | interface Bird {
67 | hasBeak: boolean;
68 | flap: () => void;
69 | }
70 | ```
71 |
72 | These two are the exact same inside TypeScript. The basic rule for TypeScript’s structural type system is that
73 | `x` is compatible with `y` if `y` has at least the same members as `x`.
74 |
75 | * `Laziness` To support language services that respond interactively, the compiler is lazy: it does not calculate any information until it is required.
76 | This allows it to respond quickly when the language service requests the type of a variable or its members.
77 | Unfortunately, laziness also makes the compiler code more complicated.
78 |
79 | As an overview, after parsing is complete, the binder does nothing but identify symbols.
80 | The checker then waits until a particular symbol is requested to calculate type information, etc.
81 |
82 | * `Immutability` - Each phase of the compiler (parser, binder, etc -- see below for details) treats data structures from the previous phases as immutable.
83 | In addition, data structures created within each phase are not usually modified after their creation.
84 | This requires a look-aside table in some cases.
85 | For example, because the binder only looks at one file at a time, the checker needs a merged-symbols table to track merged declarations.
86 | It checks whether a symbol has an entry in the merged-symbols table each time before it uses a symbol.
87 |
88 | - `Literal` - A literal type is a type that only has a single value, e.g. `true`, `1`, `"abc"`, `undefined`.
89 |
90 | For immutable objects, TypeScript creates a literal type which is the value. For mutable objects TypeScript
91 | uses the general type that the literal matches. See [#10676](https://github.com/Microsoft/TypeScript/pull/10676)
92 | for a longer explanation.
93 |
94 | ```ts
95 | // The types are the literal:
96 | const c1 = 1; // Type 1
97 | const c2 = c1; // Type 1
98 | const c3 = "abc"; // Type "abc"
99 | const c4 = true; // Type true
100 | const c5 = c4 ? 1 : "abc"; // Type 1 | "abc"
101 |
102 | // The types are the class of the literal, because let allows it to change
103 | let v1 = 1; // Type number
104 | let v2 = c2; // Type number
105 | let v3 = c3; // Type string
106 | let v4 = c4; // Type boolean
107 | let v5 = c5; // Type number | string
108 | ```
109 |
110 | Literal types are sometimes called unit types, because they have only one ("unit") value.
111 |
112 | * `Control Flow Analysis` - using the natural branching and execution path of code to change the types at
113 | different locations in your source code by static analysis.
114 |
115 | ```ts
116 | type Bird = { color: string; flaps: true };
117 | type Tiger = { color: string; stripes: true };
118 | declare;
119 | animal: Bird | Tiger;
120 |
121 | if ("stripes" in animal) {
122 | // Inside here animal is only a tiger, because TS could figure out that
123 | // the only way you could get here is when animal is a tiger and not a bird
124 | }
125 | ```
126 |
127 | * `Generics` - A way to have variables inside a type system.
128 |
129 | ```ts
130 | function first(array: any[]): any {
131 | return array[0];
132 | }
133 | ```
134 |
135 | You want to be able to pass a variable type into this function, so you annotate the function with angle brackets
136 | and a _type parameter_:
137 |
138 | ```ts
139 | function first(array: T[]): T {
140 | return array[0];
141 | }
142 | ```
143 |
144 | This means the return type of `first` is the same as the type of the array elements passed in. (These can start
145 | looking very complicated over time, but the principle is the same; it just looks more complicated because of the
146 | single letter.) Generic functions should always use their type parameters in more than one position (e.g. above,
147 | `T` is used both in the type of the `array` parameter and in the function’s return type). This is the heart of
148 | what makes generics useful—they can specify a _relationship_ between two types (e.g., a function’s output is the
149 | same as input, or a function’s two inputs are the same type). If a generic only uses its type parameter once, it
150 | doesn’t actually need to be generic at all, and indeed some linters will warn that it’s a _useless generic_.
151 |
152 | Type parameters can usually be inferred from function arguments when calling generics:
153 |
154 | ```ts
155 | first([1, 2, 3]); // 'T' is inferred as 'number'
156 | ```
157 |
158 | It’s also possible to specify them explicitly, but it’s preferable to let inference work when possible:
159 |
160 | ```ts
161 | first(["a", "b", "c"]);
162 | ```
163 |
164 | - `Outer type parameter` - A type parameter declared in a parent generic construct:
165 |
166 | ```ts
167 | class Parent {
168 | method(x: T, y: U): U {
169 | // 'T' is an *outer* type parameter of 'method'
170 | // 'U' is a *local* type parameter of 'method'
171 | }
172 | }
173 | ```
174 |
175 | - `Narrowing` - Taking a union of types and reducing it to fewer options.
176 |
177 | A great case is when using `--strictNullCheck` when using control flow analysis
178 |
179 | ```ts
180 | // I have a dog here, or I don't
181 | declare const myDog: Dog | undefined;
182 |
183 | // Outside the if, myDog = Dog | undefined
184 | if (dog) {
185 | // Inside the if, myDog = Dog
186 | // because the type union was narrowed via the if statement
187 | dog.bark();
188 | }
189 | ```
190 |
191 | * `Expanding` - The opposite of narrowing, taking a type and converting it to have more potential values.
192 |
193 | ```ts
194 | const helloWorld = "Hello World"; // Type; "Hello World"
195 |
196 | let onboardingMessage = helloWorld; // Type: string
197 | ```
198 |
199 | When the `helloWorld` constant was re-used in a mutable variable `onboardingMessage` the type which was set is an
200 | expanded version of `"Hello World"` which went from one value ever, to any known string.
201 |
202 | - `Transient` - a symbol created in the checker.
203 |
204 | The checker creates its own symbols for unusual declarations:
205 |
206 | 1. Cross-file declarations
207 |
208 | ```ts
209 | // @filename: one.ts
210 | interface I {
211 | a;
212 | }
213 | // @filename: two.ts
214 | interface I {
215 | b;
216 | }
217 | ```
218 |
219 | The binder creates two symbols for I, one in each file. Then the checker creates a merged symbol that has both declarations.
220 |
221 | 2. Synthetic properties
222 |
223 | ```ts
224 | type Nats = Record<"one" | "two", number>;
225 | ```
226 |
227 | The binder doesn't create any symbols for `one` or `two`, because those properties don't exist until the Record mapped type creates them.
228 |
229 | 3. Complex JS patterns
230 |
231 | ```js
232 | var f = function g() {
233 | g.expando1 = {};
234 | };
235 | f.expando2 = {};
236 | ```
237 |
238 | People can put expando properties on a function expression inside or outside the function, using different names.
239 |
240 | - `Partial Type` -
241 | - `Synthetic` - a property that doesn't have a declaration in source.
242 | - `Union Types`
243 | - `Enum`
244 | - `Discriminant`
245 | - `Intersection`
246 | - `Indexed Type` - A way to access subsets of your existing types.
247 |
248 | ```ts
249 | interface User {
250 | profile: {
251 | name: string;
252 | email: string;
253 | bio: string;
254 | };
255 | account: {
256 | id: string;
257 | signedUpForMailingList: boolean;
258 | };
259 | }
260 |
261 | type UserProfile = User["profile"]; // { name: string, email: string, bio: string }
262 | type UserAccount = User["account"]; // { id: string, signedUpForMailingList: string }
263 | ```
264 |
265 | This makes it easier to keep a single source of truth in your types.
266 |
267 | - `Index Signatures` - A way to tell TypeScript that you might not know the keys, but you know the type of values
268 | of an object.
269 |
270 | ```ts
271 | interface MySettings {
272 | [index: string]: boolean;
273 | }
274 |
275 | declare function getSettings(): MySettings;
276 | const settings = getSettings();
277 | const shouldAutoRotate = settings.allowRotation; // boolean
278 | ```
279 |
280 | - `IndexedAccess` - ( https://github.com/Microsoft/TypeScript/pull/30769 )
281 | - `Conditional Types`
282 | - `Contextual Types`
283 | - `Substitution`
284 | - `NonPrimitive`
285 | - `Instantiable`
286 | - `Tuple` - A mathematical term for a finite ordered list. Like an array but with a known length.
287 |
288 | TypeScript lets you use these as convenient containers with known types.
289 |
290 | ```ts
291 | // Any item has to say what it is, and whether it is done
292 | type TodoListItem = [string, boolean];
293 |
294 | const chores: TodoListItem[] = [
295 | ["read a book", true],
296 | ["done dishes", true],
297 | ["take the dog out", false],
298 | ];
299 | ```
300 |
301 | Yes, you could use an object for each item in this example, but tuples are there when it fits your needs.
302 |
303 | - `Mapped Type` - A type which works by taking an existing type and creating a new version with modifications.
304 |
305 | ```ts
306 | type Readonly = { readonly [P in keyof T]: T[P] };
307 |
308 | // Map for every key in T to be a readonly version of it
309 | // e.g.
310 | interface Dog {
311 | furColor: string;
312 | hasCollar: boolean;
313 | }
314 |
315 | // Using this
316 | type ReadOnlyDog = Readonly;
317 |
318 | // Would be
319 | interface ReadonlyDog {
320 | readonly furColor: string;
321 | readonly hasCollar: boolean;
322 | }
323 | ```
324 |
325 | This can work where you
326 |
327 | - `Type Assertion` - override its inferred and analyzed view of a type
328 |
329 | ```ts
330 | interface Foo {
331 | bar: number;
332 | bas: string;
333 | }
334 | var foo = {} as Foo;
335 | foo.bar = 123;
336 | foo.bas = "hello";
337 | ```
338 |
339 | - `Incremental Parsing` - Having an editor pass a range of edits, and using that range to invalidate a cache of
340 | the AST. Re-running the type checker will keep the out of range nodes and only parse the new section.
341 | - `Incremental Compiling` - The compiler keeps track of all compilation hashes, and timestamps when a file has
342 | been transpiled. Then when a new module is changed, it will use the import/export dependency graph to invalidate
343 | and re-compile only the affected code.
344 |
345 | ### Rarely heard
346 |
347 | - `Deferred`
348 | - `Homomorphic`
349 |
350 | ### JS Internals Specifics
351 |
352 | [`Statement`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements) - "JavaScript
353 | applications consist of statements with an appropriate syntax. A single statement may span multiple lines.
354 | Multiple statements may occur on a single line if each statement is separated by a semicolon. This isn't a
355 | keyword, but a group of keywords."
356 |
357 | [wnn]: https://github.com/sandersn/manual/blob/master/Widening-and-Narrowing-in-Typescript.md
358 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Attribution 4.0 International
2 |
3 | =======================================================================
4 |
5 | Creative Commons Corporation ("Creative Commons") is not a law firm and
6 | does not provide legal services or legal advice. Distribution of
7 | Creative Commons public licenses does not create a lawyer-client or
8 | other relationship. Creative Commons makes its licenses and related
9 | information available on an "as-is" basis. Creative Commons gives no
10 | warranties regarding its licenses, any material licensed under their
11 | terms and conditions, or any related information. Creative Commons
12 | disclaims all liability for damages resulting from their use to the
13 | fullest extent possible.
14 |
15 | Using Creative Commons Public Licenses
16 |
17 | Creative Commons public licenses provide a standard set of terms and
18 | conditions that creators and other rights holders may use to share
19 | original works of authorship and other material subject to copyright
20 | and certain other rights specified in the public license below. The
21 | following considerations are for informational purposes only, are not
22 | exhaustive, and do not form part of our licenses.
23 |
24 | Considerations for licensors: Our public licenses are
25 | intended for use by those authorized to give the public
26 | permission to use material in ways otherwise restricted by
27 | copyright and certain other rights. Our licenses are
28 | irrevocable. Licensors should read and understand the terms
29 | and conditions of the license they choose before applying it.
30 | Licensors should also secure all rights necessary before
31 | applying our licenses so that the public can reuse the
32 | material as expected. Licensors should clearly mark any
33 | material not subject to the license. This includes other CC-
34 | licensed material, or material used under an exception or
35 | limitation to copyright. More considerations for licensors:
36 | wiki.creativecommons.org/Considerations_for_licensors
37 |
38 | Considerations for the public: By using one of our public
39 | licenses, a licensor grants the public permission to use the
40 | licensed material under specified terms and conditions. If
41 | the licensor's permission is not necessary for any reason--for
42 | example, because of any applicable exception or limitation to
43 | copyright--then that use is not regulated by the license. Our
44 | licenses grant only permissions under copyright and certain
45 | other rights that a licensor has authority to grant. Use of
46 | the licensed material may still be restricted for other
47 | reasons, including because others have copyright or other
48 | rights in the material. A licensor may make special requests,
49 | such as asking that all changes be marked or described.
50 | Although not required by our licenses, you are encouraged to
51 | respect those requests where reasonable. More_considerations
52 | for the public:
53 | wiki.creativecommons.org/Considerations_for_licensees
54 |
55 | =======================================================================
56 |
57 | Creative Commons Attribution 4.0 International Public License
58 |
59 | By exercising the Licensed Rights (defined below), You accept and agree
60 | to be bound by the terms and conditions of this Creative Commons
61 | Attribution 4.0 International Public License ("Public License"). To the
62 | extent this Public License may be interpreted as a contract, You are
63 | granted the Licensed Rights in consideration of Your acceptance of
64 | these terms and conditions, and the Licensor grants You such rights in
65 | consideration of benefits the Licensor receives from making the
66 | Licensed Material available under these terms and conditions.
67 |
68 |
69 | Section 1 -- Definitions.
70 |
71 | a. Adapted Material means material subject to Copyright and Similar
72 | Rights that is derived from or based upon the Licensed Material
73 | and in which the Licensed Material is translated, altered,
74 | arranged, transformed, or otherwise modified in a manner requiring
75 | permission under the Copyright and Similar Rights held by the
76 | Licensor. For purposes of this Public License, where the Licensed
77 | Material is a musical work, performance, or sound recording,
78 | Adapted Material is always produced where the Licensed Material is
79 | synched in timed relation with a moving image.
80 |
81 | b. Adapter's License means the license You apply to Your Copyright
82 | and Similar Rights in Your contributions to Adapted Material in
83 | accordance with the terms and conditions of this Public License.
84 |
85 | c. Copyright and Similar Rights means copyright and/or similar rights
86 | closely related to copyright including, without limitation,
87 | performance, broadcast, sound recording, and Sui Generis Database
88 | Rights, without regard to how the rights are labeled or
89 | categorized. For purposes of this Public License, the rights
90 | specified in Section 2(b)(1)-(2) are not Copyright and Similar
91 | Rights.
92 |
93 | d. Effective Technological Measures means those measures that, in the
94 | absence of proper authority, may not be circumvented under laws
95 | fulfilling obligations under Article 11 of the WIPO Copyright
96 | Treaty adopted on December 20, 1996, and/or similar international
97 | agreements.
98 |
99 | e. Exceptions and Limitations means fair use, fair dealing, and/or
100 | any other exception or limitation to Copyright and Similar Rights
101 | that applies to Your use of the Licensed Material.
102 |
103 | f. Licensed Material means the artistic or literary work, database,
104 | or other material to which the Licensor applied this Public
105 | License.
106 |
107 | g. Licensed Rights means the rights granted to You subject to the
108 | terms and conditions of this Public License, which are limited to
109 | all Copyright and Similar Rights that apply to Your use of the
110 | Licensed Material and that the Licensor has authority to license.
111 |
112 | h. Licensor means the individual(s) or entity(ies) granting rights
113 | under this Public License.
114 |
115 | i. Share means to provide material to the public by any means or
116 | process that requires permission under the Licensed Rights, such
117 | as reproduction, public display, public performance, distribution,
118 | dissemination, communication, or importation, and to make material
119 | available to the public including in ways that members of the
120 | public may access the material from a place and at a time
121 | individually chosen by them.
122 |
123 | j. Sui Generis Database Rights means rights other than copyright
124 | resulting from Directive 96/9/EC of the European Parliament and of
125 | the Council of 11 March 1996 on the legal protection of databases,
126 | as amended and/or succeeded, as well as other essentially
127 | equivalent rights anywhere in the world.
128 |
129 | k. You means the individual or entity exercising the Licensed Rights
130 | under this Public License. Your has a corresponding meaning.
131 |
132 |
133 | Section 2 -- Scope.
134 |
135 | a. License grant.
136 |
137 | 1. Subject to the terms and conditions of this Public License,
138 | the Licensor hereby grants You a worldwide, royalty-free,
139 | non-sublicensable, non-exclusive, irrevocable license to
140 | exercise the Licensed Rights in the Licensed Material to:
141 |
142 | a. reproduce and Share the Licensed Material, in whole or
143 | in part; and
144 |
145 | b. produce, reproduce, and Share Adapted Material.
146 |
147 | 2. Exceptions and Limitations. For the avoidance of doubt, where
148 | Exceptions and Limitations apply to Your use, this Public
149 | License does not apply, and You do not need to comply with
150 | its terms and conditions.
151 |
152 | 3. Term. The term of this Public License is specified in Section
153 | 6(a).
154 |
155 | 4. Media and formats; technical modifications allowed. The
156 | Licensor authorizes You to exercise the Licensed Rights in
157 | all media and formats whether now known or hereafter created,
158 | and to make technical modifications necessary to do so. The
159 | Licensor waives and/or agrees not to assert any right or
160 | authority to forbid You from making technical modifications
161 | necessary to exercise the Licensed Rights, including
162 | technical modifications necessary to circumvent Effective
163 | Technological Measures. For purposes of this Public License,
164 | simply making modifications authorized by this Section 2(a)
165 | (4) never produces Adapted Material.
166 |
167 | 5. Downstream recipients.
168 |
169 | a. Offer from the Licensor -- Licensed Material. Every
170 | recipient of the Licensed Material automatically
171 | receives an offer from the Licensor to exercise the
172 | Licensed Rights under the terms and conditions of this
173 | Public License.
174 |
175 | b. No downstream restrictions. You may not offer or impose
176 | any additional or different terms or conditions on, or
177 | apply any Effective Technological Measures to, the
178 | Licensed Material if doing so restricts exercise of the
179 | Licensed Rights by any recipient of the Licensed
180 | Material.
181 |
182 | 6. No endorsement. Nothing in this Public License constitutes or
183 | may be construed as permission to assert or imply that You
184 | are, or that Your use of the Licensed Material is, connected
185 | with, or sponsored, endorsed, or granted official status by,
186 | the Licensor or others designated to receive attribution as
187 | provided in Section 3(a)(1)(A)(i).
188 |
189 | b. Other rights.
190 |
191 | 1. Moral rights, such as the right of integrity, are not
192 | licensed under this Public License, nor are publicity,
193 | privacy, and/or other similar personality rights; however, to
194 | the extent possible, the Licensor waives and/or agrees not to
195 | assert any such rights held by the Licensor to the limited
196 | extent necessary to allow You to exercise the Licensed
197 | Rights, but not otherwise.
198 |
199 | 2. Patent and trademark rights are not licensed under this
200 | Public License.
201 |
202 | 3. To the extent possible, the Licensor waives any right to
203 | collect royalties from You for the exercise of the Licensed
204 | Rights, whether directly or through a collecting society
205 | under any voluntary or waivable statutory or compulsory
206 | licensing scheme. In all other cases the Licensor expressly
207 | reserves any right to collect such royalties.
208 |
209 |
210 | Section 3 -- License Conditions.
211 |
212 | Your exercise of the Licensed Rights is expressly made subject to the
213 | following conditions.
214 |
215 | a. Attribution.
216 |
217 | 1. If You Share the Licensed Material (including in modified
218 | form), You must:
219 |
220 | a. retain the following if it is supplied by the Licensor
221 | with the Licensed Material:
222 |
223 | i. identification of the creator(s) of the Licensed
224 | Material and any others designated to receive
225 | attribution, in any reasonable manner requested by
226 | the Licensor (including by pseudonym if
227 | designated);
228 |
229 | ii. a copyright notice;
230 |
231 | iii. a notice that refers to this Public License;
232 |
233 | iv. a notice that refers to the disclaimer of
234 | warranties;
235 |
236 | v. a URI or hyperlink to the Licensed Material to the
237 | extent reasonably practicable;
238 |
239 | b. indicate if You modified the Licensed Material and
240 | retain an indication of any previous modifications; and
241 |
242 | c. indicate the Licensed Material is licensed under this
243 | Public License, and include the text of, or the URI or
244 | hyperlink to, this Public License.
245 |
246 | 2. You may satisfy the conditions in Section 3(a)(1) in any
247 | reasonable manner based on the medium, means, and context in
248 | which You Share the Licensed Material. For example, it may be
249 | reasonable to satisfy the conditions by providing a URI or
250 | hyperlink to a resource that includes the required
251 | information.
252 |
253 | 3. If requested by the Licensor, You must remove any of the
254 | information required by Section 3(a)(1)(A) to the extent
255 | reasonably practicable.
256 |
257 | 4. If You Share Adapted Material You produce, the Adapter's
258 | License You apply must not prevent recipients of the Adapted
259 | Material from complying with this Public License.
260 |
261 |
262 | Section 4 -- Sui Generis Database Rights.
263 |
264 | Where the Licensed Rights include Sui Generis Database Rights that
265 | apply to Your use of the Licensed Material:
266 |
267 | a. for the avoidance of doubt, Section 2(a)(1) grants You the right
268 | to extract, reuse, reproduce, and Share all or a substantial
269 | portion of the contents of the database;
270 |
271 | b. if You include all or a substantial portion of the database
272 | contents in a database in which You have Sui Generis Database
273 | Rights, then the database in which You have Sui Generis Database
274 | Rights (but not its individual contents) is Adapted Material; and
275 |
276 | c. You must comply with the conditions in Section 3(a) if You Share
277 | all or a substantial portion of the contents of the database.
278 |
279 | For the avoidance of doubt, this Section 4 supplements and does not
280 | replace Your obligations under this Public License where the Licensed
281 | Rights include other Copyright and Similar Rights.
282 |
283 |
284 | Section 5 -- Disclaimer of Warranties and Limitation of Liability.
285 |
286 | a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
287 | EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
288 | AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
289 | ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
290 | IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
291 | WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
292 | PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
293 | ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
294 | KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
295 | ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
296 |
297 | b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
298 | TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
299 | NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
300 | INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
301 | COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
302 | USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
303 | ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
304 | DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
305 | IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
306 |
307 | c. The disclaimer of warranties and limitation of liability provided
308 | above shall be interpreted in a manner that, to the extent
309 | possible, most closely approximates an absolute disclaimer and
310 | waiver of all liability.
311 |
312 |
313 | Section 6 -- Term and Termination.
314 |
315 | a. This Public License applies for the term of the Copyright and
316 | Similar Rights licensed here. However, if You fail to comply with
317 | this Public License, then Your rights under this Public License
318 | terminate automatically.
319 |
320 | b. Where Your right to use the Licensed Material has terminated under
321 | Section 6(a), it reinstates:
322 |
323 | 1. automatically as of the date the violation is cured, provided
324 | it is cured within 30 days of Your discovery of the
325 | violation; or
326 |
327 | 2. upon express reinstatement by the Licensor.
328 |
329 | For the avoidance of doubt, this Section 6(b) does not affect any
330 | right the Licensor may have to seek remedies for Your violations
331 | of this Public License.
332 |
333 | c. For the avoidance of doubt, the Licensor may also offer the
334 | Licensed Material under separate terms or conditions or stop
335 | distributing the Licensed Material at any time; however, doing so
336 | will not terminate this Public License.
337 |
338 | d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
339 | License.
340 |
341 |
342 | Section 7 -- Other Terms and Conditions.
343 |
344 | a. The Licensor shall not be bound by any additional or different
345 | terms or conditions communicated by You unless expressly agreed.
346 |
347 | b. Any arrangements, understandings, or agreements regarding the
348 | Licensed Material not stated herein are separate from and
349 | independent of the terms and conditions of this Public License.
350 |
351 |
352 | Section 8 -- Interpretation.
353 |
354 | a. For the avoidance of doubt, this Public License does not, and
355 | shall not be interpreted to, reduce, limit, restrict, or impose
356 | conditions on any use of the Licensed Material that could lawfully
357 | be made without permission under this Public License.
358 |
359 | b. To the extent possible, if any provision of this Public License is
360 | deemed unenforceable, it shall be automatically reformed to the
361 | minimum extent necessary to make it enforceable. If the provision
362 | cannot be reformed, it shall be severed from this Public License
363 | without affecting the enforceability of the remaining terms and
364 | conditions.
365 |
366 | c. No term or condition of this Public License will be waived and no
367 | failure to comply consented to unless expressly agreed to by the
368 | Licensor.
369 |
370 | d. Nothing in this Public License constitutes or may be interpreted
371 | as a limitation upon, or waiver of, any privileges and immunities
372 | that apply to the Licensor or You, including from the legal
373 | processes of any jurisdiction or authority.
374 |
375 |
376 | =======================================================================
377 |
378 | Creative Commons is not a party to its public
379 | licenses. Notwithstanding, Creative Commons may elect to apply one of
380 | its public licenses to material it publishes and in those instances
381 | will be considered the “Licensor.” The text of the Creative Commons
382 | public licenses is dedicated to the public domain under the CC0 Public
383 | Domain Dedication. Except for the limited purpose of indicating that
384 | material is shared under a Creative Commons public license or as
385 | otherwise permitted by the Creative Commons policies published at
386 | creativecommons.org/policies, Creative Commons does not authorize the
387 | use of the trademark "Creative Commons" or any other trademark or logo
388 | of Creative Commons without its prior written consent including,
389 | without limitation, in connection with any unauthorized modifications
390 | to any of its public licenses or any other arrangements,
391 | understandings, or agreements concerning use of licensed material. For
392 | the avoidance of doubt, this paragraph does not form part of the
393 | public licenses.
394 |
395 | Creative Commons may be contacted at creativecommons.org.
--------------------------------------------------------------------------------
/LICENSE-CODE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) Microsoft Corporation.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # TypeScript Compiler Notes
2 |
3 | This repo is a corpus of notes from many engineers over time on different systems inside the TypeScript codebase. It is not meant as a "one true" source of authoritative documentation for the TypeScript compiler API, but as a way to ease contributions to the [`microsoft/TypeScript`](https://github.com/microsoft/TypeScript) repo.
4 |
5 | If you're already familiar with the TypeScript codebase and want to help out, we're open to external folks sending PRs improving or adding areas!
6 |
7 | ## Get Started
8 |
9 | If you are completely new to the TypeScript codebase, this YouTube video covers all of the major systems involved in converting files to JavaScript, and type-checking types which will provide a high level guide to what you may be interested in focusing on:
10 |
11 |
12 |
13 |
14 |
15 | If you are really short on time, here is a quick overview of the compilation process.
16 |
17 | The process starts with preprocessing.
18 | The preprocessor figures out what files should be included in the compilation by following references (`/// ` tags, `require` and `import` statements).
19 |
20 | The parser then generates AST `Node`s.
21 | These are just an abstract representation of the user input in a tree format.
22 | A `SourceFile` object represents an AST for a given file with some additional information like the file name and source text.
23 |
24 | The binder then passes over the AST nodes and generates and binds `Symbol`s.
25 | One `Symbol` is created for each named entity.
26 | There is a subtle distinction but several declaration nodes can name the same entity.
27 | That means that sometimes different `Node`s will have the same `Symbol`, and each `Symbol` keeps track of its declaration `Node`s.
28 | For example, a `class` and a `namespace` with the same name can *merge* and will have the same `Symbol`.
29 | The binder also handles scopes and makes sure that each `Symbol` is created in the correct enclosing scope.
30 |
31 | Generating a `SourceFile` (along with its `Symbol`s) is done through calling the `createSourceFile` API.
32 |
33 | So far, `Symbol`s represent named entities as seen within a single file, but several declarations can merge multiple files, so the next step is to build a global view of all files in the compilation by building a `Program`.
34 |
35 | A `Program` is a collection of `SourceFile`s and a set of `CompilerOptions`.
36 | A `Program` is created by calling the `createProgram` API.
37 |
38 | From a `Program` instance a `TypeChecker` can be created.
39 | `TypeChecker` is the core of the TypeScript type system.
40 | It is the part responsible for figuring out relationships between `Symbols` from different files, assigning `Type`s to `Symbol`s, and generating any semantic `Diagnostic`s (i.e. errors).
41 |
42 | The first thing a `TypeChecker` will do is to consolidate all the `Symbol`s from different `SourceFile`s into a single view, and build a single Symbol Table by "merging" any common `Symbol`s (e.g. `namespace`s spanning multiple files).
43 |
44 | After initializing the original state, the `TypeChecker` is ready to answer any questions about the program.
45 | Such "questions" might be:
46 | * What is the `Symbol` for this `Node`?
47 | * What is the `Type` of this `Symbol`?
48 | * What `Symbol`s are visible in this portion of the AST?
49 | * What are the available `Signature`s for a function declaration?
50 | * What errors should be reported for a file?
51 |
52 | The `TypeChecker` computes everything lazily; it only "resolves" the necessary information to answer a question.
53 | The checker will only examine `Node`s/`Symbol`s/`Type`s that contribute to the question at hand and will not attempt to examine additional entities.
54 |
55 | An `Emitter` can also be created from a given `Program`.
56 | The `Emitter` is responsible for generating the desired output for a given `SourceFile`; this includes `.js`, `.jsx`, `.d.ts`, and `.js.map` outputs.
57 |
58 |
59 |
60 | From there, you can start in the [First Steps to Contributing to the TypeScript Repo](https://github.com/microsoft/TypeScript-Compiler-Notes/tree/main/intro#the-typescript-compiler) consult the [Glossary](./GLOSSARY.md) or dive directly into the [`./codebase/`](./codebase) or [`./systems/`](./systems) folders.
61 |
62 | ## Asking Questions
63 |
64 | One of the best places to ask questions is in the 'compiler-internals-and-api' channel of the [TypeScript Community Discord](https://discord.gg/typescript).
65 |
66 | ## Related TypeScript Info
67 |
68 | - Learn how TypeScript works by reading the [mini-TypeScript implementation](https://github.com/sandersn/mini-typescript#mini-typescript)
69 | - [Basarat's guide to the Compiler Internals](https://basarat.gitbook.io/typescript/overview)
70 |
71 | ## Compilers in General
72 |
73 | - Recommended link for learning how compilers work: https://c9x.me/compile/bib/
74 |
75 | ## Interesting PRs
76 |
77 | If you learn better by seeing how big features are added to TypeScript, here are a few big well-scoped Pull Requests:
78 |
79 | - Unions - [microsoft/TypeScript#824](https://github.com/microsoft/TypeScript/pull/824)
80 | - Type Aliases - [microsoft/TypeScript#957](https://github.com/microsoft/TypeScript/pull/957)
81 | - Async Functions - [microsoft/TypeScript#3078](https://github.com/microsoft/TypeScript/pull/3078)
82 | - TSX - [microsoft/TypeScript#3564](https://github.com/microsoft/TypeScript/pull/3564)
83 | - Intersection Types - [microsoft/TypeScript#3622](https://github.com/microsoft/TypeScript/pull/3622)
84 | - String Literal Types - [microsoft/TypeScript#5185](https://github.com/microsoft/TypeScript/pull/5185)
85 | - JS in TS - [microsoft/TypeScript#5266](https://github.com/microsoft/TypeScript/pull/5266)
86 | - Using JSDoc to extract types - [microsoft/TypeScript#6024](https://github.com/microsoft/TypeScript/pull/6024)
87 | - Nullable types - [microsoft/TypeScript#7140](https://github.com/microsoft/TypeScript/pull/7140)
88 | - Control Flow Analysis - [microsoft/TypeScript#8010](https://github.com/microsoft/TypeScript/pull/8010)
89 | - Mapped Types - [microsoft/TypeScript#12114](https://github.com/microsoft/TypeScript/pull/12114)
90 | - Rest Types - [microsoft/TypeScript#13470](https://github.com/microsoft/TypeScript/pull/13470)
91 | - Strict Functions - [microsoft/TypeScript#18654](https://github.com/microsoft/TypeScript/pull/18654)
92 | - Unknown - [microsoft/TypeScript#24439](https://github.com/microsoft/TypeScript/pull/24439)
93 | - Optional Chaining - [microsoft/TypeScript#33294](https://github.com/microsoft/TypeScript/pull/33294)
94 | - Node ESM Support - [microsoft/TypeScript#45884](https://github.com/microsoft/TypeScript/pull/45884)
95 |
96 | # Contributing
97 |
98 | This project welcomes contributions and suggestions. Most contributions require you to agree to a
99 | Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
100 | the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com.
101 |
102 | When you submit a pull request, a CLA bot will automatically determine whether you need to provide
103 | a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions
104 | provided by the bot. You will only need to do this once across all repos using our CLA.
105 |
106 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
107 | For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
108 | contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
109 |
110 | # Legal Notices
111 |
112 | Microsoft and any contributors grant you a license to the Microsoft documentation and other content
113 | in this repository under the [Creative Commons Attribution 4.0 International Public License](https://creativecommons.org/licenses/by/4.0/legalcode),
114 | see the [LICENSE](LICENSE) file, and grant you a license to any code in the repository under the [MIT License](https://opensource.org/licenses/MIT), see the
115 | [LICENSE-CODE](LICENSE-CODE) file.
116 |
117 | Microsoft, Windows, Microsoft Azure and/or other Microsoft products and services referenced in the documentation
118 | may be either trademarks or registered trademarks of Microsoft in the United States and/or other countries.
119 | The licenses for this project do not grant you rights to use any Microsoft names, logos, or trademarks.
120 | Microsoft's general trademark guidelines can be found at http://go.microsoft.com/fwlink/?LinkID=254653.
121 |
122 | Privacy information can be found at https://privacy.microsoft.com/en-us/
123 |
124 | Microsoft and any contributors reserve all other rights, whether under their respective copyrights, patents,
125 | or trademarks, whether by implication, estoppel or otherwise.
126 |
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ## Security
4 |
5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).
6 |
7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)), please report it to us as described below.
8 |
9 | ## Reporting Security Issues
10 |
11 | **Please do not report security vulnerabilities through public GitHub issues.**
12 |
13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report).
14 |
15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/en-us/msrc/pgp-key-msrc).
16 |
17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc).
18 |
19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
20 |
21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
22 | * Full paths of source file(s) related to the manifestation of the issue
23 | * The location of the affected source code (tag/branch/commit or direct URL)
24 | * Any special configuration required to reproduce the issue
25 | * Step-by-step instructions to reproduce the issue
26 | * Proof-of-concept or exploit code (if possible)
27 | * Impact of the issue, including how an attacker might exploit the issue
28 |
29 | This information will help us triage your report more quickly.
30 |
31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs.
32 |
33 | ## Preferred Languages
34 |
35 | We prefer all communications to be in English.
36 |
37 | ## Policy
38 |
39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd).
40 |
41 |
--------------------------------------------------------------------------------
/codebase/screenshots/snippet-vscode.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/TypeScript-Compiler-Notes/31425672133e15f4e61f52a0f541d060f239e915/codebase/screenshots/snippet-vscode.png
--------------------------------------------------------------------------------
/codebase/screenshots/threeslash-refs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/TypeScript-Compiler-Notes/31425672133e15f4e61f52a0f541d060f239e915/codebase/screenshots/threeslash-refs.png
--------------------------------------------------------------------------------
/codebase/src/compiler/binder.md:
--------------------------------------------------------------------------------
1 | # Binder
2 |
3 | The binder walks the tree visiting each declaration in the tree.
4 | For each declaration that it finds, it creates a `Symbol` that records its location and kind of declaration.
5 | Then it stores that symbol in a `SymbolTable` in the containing node, like a function, block or module file, that is the current scope.
6 | `Symbol`s let the checker look up names and then check their declarations to determine types.
7 | It also contains a small summary of what kind of declaration it is -- mainly whether it is a value, a type, or a namespace.
8 |
9 | Since the binder is the first tree walk before checking, it also does some other tasks: setting up the control flow graph,
10 | as well as annotating parts of the tree that will need to be downlevelled for old ES targets.
11 |
12 | Here's an example:
13 |
14 | ```ts
15 | // @Filename: main.ts
16 | var x = 1
17 | console.log(x)
18 | ```
19 |
20 | The only declaration in this program is `var x`, which is contained in the SourceFile node for `main.ts`.
21 | Functions and classes introduce new scopes, so they are containers -- at the same time as being declarations themselves. So in:
22 |
23 | ```ts
24 | function f(n: number) {
25 | const m = n + 1
26 | return m + n
27 | }
28 | ```
29 |
30 | The binder ends up with a symbol table for `f` that contains two entries: `n` and `m`.
31 | The binder finds `n` while walking the function's parameter list, and it finds `m` while walking the block that makes up `f`'s body.
32 |
33 | Both `n` and `m` are marked as values.
34 | However, there's no problem with adding another declaration for `n`:
35 |
36 | ```ts
37 | function f(n: number) {
38 | type n = string
39 | const m = n + 1
40 | return m + n
41 | }
42 | ```
43 |
44 | Now `n` has two declarations, one type and one value.
45 | The binder disallows more than one declaration of a kind of symbols with *block-scoped* declaration.
46 | Examples are `type`, `function`, `class`, `let`, `const` and parameters; *function-scoped* declarations include `var` and `interface`.
47 | But as long as the declarations are of different kinds, they're fine.
48 |
49 | ## Walkthrough
50 |
51 | ```ts
52 | function f(m: number) {
53 | type n = string
54 | const n = m + 1
55 | return m + n
56 | }
57 | ```
58 |
59 | The binder's basic tree walk starts in `bind`.
60 | There, it first encounters `f` and calls `bindFunctionDeclaration` and then `bindBlockScopeDeclaration` with `SymbolFlags.Function`.
61 | This function has special cases for files and modules, but the default case calls `declareSymbol` to add a symbol in the current container.
62 | There is a lot of special-case code in `declareSymbol`, but the important path is to check whether the symbol table already contains a symbol with the name of the declaration -- `f` in this case.
63 | If not, a new symbol is created.
64 | If so, the old symbol's exclude flags are checked against the new symbol's flags.
65 | If they conflict, the binder issues an error.
66 |
67 | Finally, the new symbol's `flags` are added to the old symbol's `flags` (if any), and the new declaration is added to the symbol's `declarations` array.
68 | In addition, if the new declaration is for a value, it is set as the symbol's `valueDeclaration`.
69 |
70 | ## Containers
71 |
72 | After `declareSymbol` is done, the `bind` visits the children of `f`; `f` is a container, so it calls `bindContainer` before `bindChildren`.
73 | The binder is recursive, so it pushes `f` as the new container by copying it to a local variable before walking its children.
74 | It pops `f` by copying the stored local back into `container`.
75 |
76 | The binder tracks the current lexical container as a pair of variables `container` and `blockScopedContainer` (and `thisParentContainer` if you OOP by mistake).
77 | It's implemented as a global variable managed by the binder walk, which pushes and pops containers as needed.
78 | The container's symbol table is initialised lazily, by `bindBlockScopedDeclaration`, for example.
79 |
80 | ## Flags
81 |
82 | The table for which symbols may merge with each other is complicated, but it's implemented in a surprisingly small space using the bitflag enum `SymbolFlags`.
83 | The downside is that the bitflag system is very confusing.
84 |
85 | The basic rule is that a new declaration's *flags* may not conflict with the *excludes flags* of any previous declarations.
86 | Each kind of declaration has its own exclude flags; each one is a list of declaration kinds that cannot merge with that declaration.
87 |
88 | In the example above, `type n` is a type alias, which has flags = `SymbolFlags.TypeAlias` and excludeFlags = `SymbolFlags.TypeAliasExcludes`.
89 | The latter is an alias of `SymbolFlags.Type`, meaning generally that type aliases can't merge with anything that declares a type:
90 |
91 | ```ts
92 | Type = Class | Interface | Enum | EnumMember | TypeLiteral | TypeParameter | TypeAlias
93 | ```
94 | Notice that this list includes `TypeAlias` itself, and declarations like classes and enums that also declare values.
95 | `Value` includes `Class` and `Enum` as well.
96 |
97 | Next, when the binder reaches `const n`, it uses the flag `BlockScopedVariable` and excludeFlags `BlockScopedVariableExcludes`.
98 | `BlockScopedVariableExcludes = Value`, which is a list of every kind of value declaration.
99 |
100 | ```ts
101 | Value = Variable | Property | EnumMember | ObjectLiteral | Function | Class | Enum | ValueModule | Method | GetAccessor | SetAccessor
102 | ```
103 |
104 | `declareSymbol` looks up the existing excludeFlags for `n` and makes sure that `BlockScopedVariable` doesn't conflict; `BlockScopedVariable & Type === 0` so it doesn't.
105 | Then it *or*s the new and old flags and the new and old excludeFlags.
106 | In this example, that will prevent more value declarations because `BlockScopedVariable & (Value | Type) !== 0`.
107 |
108 | Here's some half-baked example code which shows off what you'd write if SymbolFlags used string enums and sets instead of bitflags.
109 |
110 | ```ts
111 | const existing = symbolTable.get(name)
112 | const flags = SymbolFlags[declaration.kind] // eg "Function"
113 | if (existing.excludes.has(flags)) {
114 | error("Cannot redeclare", name)
115 | }
116 | existing.flags.add(flags)
117 | for (const ex of ExcludeFlags[declaration.kind]) {
118 | existing.excludeFlags.add(ex)
119 | }
120 | ```
121 |
122 | ## Cross-file global merges
123 |
124 | Because the binder only binds one file at a time, the above system for merges only works with single files.
125 | For global (aka script) files, declarations can merge across files.
126 | This happens in the checker in `initializeTypeChecker`, using `mergeSymbolTable`.
127 |
128 | ## Special names
129 |
130 | In `declareSymbol`, `getDeclarationName` translates certain nodes into internal names.
131 | `export=`, for example, gets translated to `InternalSymbolName.ExportEquals`
132 |
133 | Elsewhere in the binder, function expressions without names get `"__function"`
134 | Computed property names that aren't literals get `"__computed"`, manually.
135 |
136 | TODO: Finish this
137 |
138 | ## Control Flow
139 |
140 | TODO: Missing completely
141 |
142 | ## Emit flags
143 |
144 | TODO: Missing completely
145 |
146 | ## Exports
147 |
148 | TODO: Missing completely
149 |
150 | ## Javascript and CommonJS
151 |
152 | Javascript has additional types of declarations that it recognises, which fall into 3 main categories:
153 |
154 | 1. Constructor functions and pre-class-field classes: assignments to `this.x` properties.
155 | 2. CommonJS: assignments to `module.exports`.
156 | 3. Global browser code: assignments to namespace-like object literals.
157 | 4. JSDoc declarations: tags like `@type` and `@callback`.
158 |
159 | Four! Four main categories!
160 |
161 | The first three categories really aren't much different from Typescript declarations.
162 | The main complication is that not all assignments are declarations, so there's quite a bit of code that decides which assignments should be treated as declarations.
163 | The checker is fairly resilient to non-declaration assignments being included, so it's OK if the code isn't perfect.
164 |
165 | In `bindWorker`'s `BinaryExpression` case, `getAssignmentDeclarationKind` is used to decide whether an assignment matches the syntactic requirements for declarations.
166 | Then each kind of assignment dispatches to a different binding function.
167 |
168 | ### Global namespace creation code
169 |
170 | In addition to CommonJS, JS also supports creating global namespaces by assignments of object literals, functions and classes to global variables.
171 | This code is very complicated and is *probably* only ever used by Closure code bases, so it might be possible to remove it someday.
172 |
173 | ``` js
174 | var Namespace = {}
175 | Namespace.Mod1 = {}
176 | Namespace.Mod2 = function () {
177 | // callable module!
178 | }
179 | Namespace.Mod2.Sub1 = {
180 | // actual contents
181 | }
182 | ```
183 |
184 | TODO: This is unfinished.
185 |
186 | ### JSDoc declarations
187 |
188 | TODO: This is unfinished.
189 |
190 | ### Conflicting object literal export assignments
191 |
192 | One particuarly complex case of CommonJS binding occurs when there is an object literal export assignment in the same module as `module.exports` assignments:
193 |
194 | ```js
195 | module.exports = {
196 | foo: function() { return 1 },
197 | bar: function() { return 'bar' },
198 | baz: 12,
199 | }
200 | if (isWindows) {
201 | // override 'foo' with Windows-specific version
202 | module.exports.foo = function () { return 11 }
203 | }
204 | ```
205 |
206 | In this case, the desired exports of the file are `foo, bar, baz`.
207 | Even though `foo` is declared twice, it should have one export with two declarations.
208 | The type should be `() => number`, though that's the responsibility of the checker.
209 |
210 | In fact, this structure is too complicated to build in the binder, so the checker produces it through merges, using the same merge infrastructure it uses for cross-file global merges.
211 | The binder treats this pretty straightforwardly; it calls `bindModuleExportsAssignment` for `module.exports = {...`, which creates a single `export=` export.
212 | Then it calls `bindExportsPropertyAssignment` for `module.exports.foo = ...`, which creates a `foo` export.
213 |
214 | Having `export=` with other exports is impossible with ES module syntax, so the checker detects it and copies all the top-level exports into the `export=`.
215 | In the checker, `resolveExternalModuleSymbol` returns either an entire module's exports, or all the exports in an `export=`.
216 | In the combined CommonJS case we're discussing, `getCommonJsExportEquals` also checks whether a module has exports *and* `export=`.
217 | If it does, it copies each of the top-level exports into the `export=`.
218 | If a property with the same name already exists in the `export=`, the two are merged with `mergeSymbol`.
219 |
220 | Subsequent code in the checker that doesn't use `resolveExternalModuleSymbol` (is there any?) has to ignore the `export=`, since its contents are now just part of the module.
221 |
--------------------------------------------------------------------------------
/codebase/src/compiler/checker-inference.md:
--------------------------------------------------------------------------------
1 |
2 | [0]: https://github.com/microsoft/TypeScript/blob/db9e0079/src/compiler/checker.ts#L21772# Type Inference
3 |
4 | TypeScript has a number of related techniques which together are
5 | called type inference: places where a type is discovered from
6 | inspecting values instead of a type annotation. This document
7 | covers them all in one place even though they're all fairly different.
8 |
9 | One thing that that is true of all type inference in TypeScript:
10 | type inference is a separate step that happens before checking. The
11 | checker will infer a type for a location; then it will check the type
12 | in the normal way, as if the type had been explicitly written. This
13 | results in redundant checking when the type inference is simple.
14 |
15 | None of these techniques are Hindley-Milner type inference. Instead,
16 | TypeScript adds a few ad-hoc inference techniques to its normal
17 | type-checking. The result is a system that can infer from many useful
18 | locations, but nowhere near all of them.
19 |
20 | ## Initialiser inference
21 |
22 | The simplest kind of inference is from initialisers. This inference is
23 | so simple that I don't believe it has been given a separate name until
24 | now.
25 |
26 | You can see this anywhere a variable, parameter or property has an
27 | initialiser:
28 |
29 | ```ts
30 | let x = 123
31 | function f(x = 123) {
32 | }
33 | class C {
34 | x = 123
35 | }
36 | ```
37 |
38 | Remember, inference precedes checking, so checking `let x = 123`
39 | looks like this:
40 |
41 | 1. Look for the type of `x`.
42 | 2. There is no annotation, so use the (widened) type of the initialiser: `number`.
43 | 3. Check that the initialiser's type `123` is assignable to `number`.
44 |
45 | ## Contextual typing
46 |
47 | Contextual typing looks upward in the tree for a type based on a type
48 | annotation. This is unlike initialiser inference, which looks at a *sibling*
49 | node for a type based on a *value*. For example, in
50 |
51 | ```ts
52 | const f: Callback = (a,b) => a.length + b
53 | ```
54 |
55 | The parameters `a` and `b` are contextually typed by the type
56 | `Callback`. The checker discovers this by looking at the parent nodes
57 | of `a` and `b` until it finds a type annotation on a variable declaration.
58 |
59 | In fact, contextual typing only applies to two kinds of things:
60 | parameters and literals (including JSX literals). But it may find a type in a variety of places.
61 | Here are 3 typical ones:
62 |
63 | 1. A type annotation on a declaration:
64 |
65 | ```ts
66 | type Config = { before(data: string): void }
67 | const cfg: Config = {
68 | before(x) {
69 | console.log(x.length)
70 | }
71 | }
72 | ```
73 |
74 | 2. The left-hand side of an assignment:
75 |
76 | ```ts
77 | let steps: ('up' | 'down' | 'left' | 'right')[] = ['up', 'up', 'down', 'down']
78 | steps = ['down']
79 | ```
80 |
81 | 3. An argument in a function call:
82 |
83 | ```ts
84 | declare function setup(register: (name: string, age: number) => void): void
85 | setup((name, age) => console.log(name, age))
86 | ```
87 |
88 | The basic mechanism of contextual typing is a search for a type
89 | annotation. Once a type annotation is found, contextual typing walks
90 | down through the *type* by reversing the path it walked up through the
91 | *tree*.
92 |
93 | Aside: In example (2), contextual typing gives `'down'` the
94 | *non-widening* type `'down'`; it would otherwise have the type
95 | `string`. That means `['down']` will have the type `'down'[]`, which
96 | is assignable to `steps`. So contextual typing lets programmers avoid
97 | writing `['down' as 'down']` in some cases.
98 |
99 | ### Walkthrough
100 |
101 | Let's walk through example (1).
102 |
103 | 1. During normal check of the tree,
104 | `checkFunctionExpressionOrObjectLiteralMethod` is called on
105 | `before`.
106 | 2. This calls `getApparentTypeofContextualType` (after a few
107 | intermediate functions), which
108 | recursively looks for the contextual type of `before`'s parent.
109 | 3. The parent is an object literal, which recursively looks for the
110 | contextual type of the object literal's parent.
111 | 4. The parent is a variable declaration with a type annotation `Config`.
112 | This is the contextual type of the object literal.
113 | 5. Next we look inside `Config` for a property named `before`. Since's
114 | `Config.before`'s type is a signature, that signature is the
115 | contextual type of `before`.
116 | 6. Finally, `assignContextualParameterTypes` assigns a type for `x` from
117 | `Config.before`'s first parameter.
118 |
119 | Note that if you have type annotations on some parameters already,
120 | `assignContextualParameterTypes` will skip those parameters.
121 |
122 | Contextually typing `(name, age) => ...` in (3) works substantially
123 | that same. When the search reaches `getContextualType`, instead of a
124 | variable declaration, the parent is a call expression. The contextual
125 | type of a call expression is the type of the callee, `setup` in this
126 | case. Now, as before, we look inside `setup`'s type: `(name, age) =>
127 | ...` is the first argument, so its contextual type is from the first
128 | parameter of `setup`, `register`. `assignmentContextualParameterTypes`
129 | works for `name` and `age` as in (1).
130 |
131 | ## Type Parameter Inference
132 |
133 | Type parameter inference is quite different from the other two
134 | techniques. It still infers **types** based on provided **values**,
135 | but the inferred types don't replace a type annotation. Instead
136 | they're provided as type arguments to a function, which results in
137 | instantiating a generic function with some specific type. For example:
138 |
139 | ```ts
140 | declare function setup(config: { initial(): T }): T
141 | setup({ initial() { return "last" } })
142 | ```
143 |
144 | First checks `{ initial() { return "last" } }` to get `{ initial():
145 | string }`. By matching `T` in `{ initial(): T }` with `string` in `{
146 | initial(): string }`, it infers that `T` is `string`, making the
147 | second line the same as if the author had written:
148 |
149 | ```ts
150 | setup({ initial() { return "last" } })
151 | ```
152 |
153 | Meaning that the compiler then checks that
154 | `{ initial() { return "last" } }` is assignable to
155 | `{ initial(): string }`.
156 |
157 | ### Walkthrough
158 |
159 | Type parameter inference starts off in `inferTypeArguments`, where
160 | the first step in type parameter inference is to get the type of all
161 | the arguments to the function whose parameters are being inferred. In
162 | the above example, the checker says that the type of
163 | `{ initial() { return "last" } }` is `{ initial(): string }`. This
164 | type is called the **source** type, since it is the source of
165 | inferences. It's matched with the parameter type `{ initial(): T }`.
166 | This is the **target** type -- it contains type parameters which are
167 | the target of the process.
168 |
169 | Type parameter inference is a pairwise walk of the two types, looking
170 | for type parameters in the target, matching them to corresponding
171 | types in the source. The type is walked structurally sort of like a tree
172 | is elsewhere in the compiler.
173 |
174 | 1. `inferTypes` gets called on each source/target pair with
175 | argument=source/parameter=target. There's only one pair here:
176 | `{ initial(): string }` and `{ initial(): T }`.
177 | 2. Since both sides are object types, `inferFromProperties` looks
178 | through each property of the target and looks for a match in the
179 | source. In this case both have the property `initial`.
180 | 3. `initial`'s type is a signature on both sides
181 | (`() => T/() => string`), so inference goes to `inferFromSignature`, which
182 | recursively infers from the return type.
183 | 4. Now the source/target pair is `T/string`. Since the source is a
184 | lone type parameter, we add `string` to the list of candidates for
185 | `T`.
186 |
187 | Once all the parameters have had `inferTypes` called on them,
188 | `getInferredTypes` condenses each candidate array to a single type,
189 | via `getUnionType` in this case. `T`'s candidates array is `[string]`,
190 | so `getUnionType` immediately returns `string`.
191 |
192 | ### Other considerations
193 |
194 | #### Method of Combining Candidate Arrays
195 |
196 | Only inference to return types, `keyof T` and mapped type constraints
197 | (which are usually `keyof` too) produce a union. These are all
198 | contravariant inference locations. All other locations
199 | call the custom code `getCommonSupertype`, which more or less does
200 | what it says. Note that object types are always unioned together
201 | first, regardless of inference position.
202 |
203 | #### Interference Between Contextual Typing and Type Parameter Inference
204 |
205 | Type parameter inference actually operates in two passes. The first
206 | pass skips arguments that have contextually typed expressions so that
207 | if good inferences are found from other arguments, contextual typing
208 | can provide types to parameters of function expressions, which in turn
209 | may produce better return types. Then the second pass proceeds with
210 | all arguments.
211 |
212 | #### Inference Priorities
213 |
214 | Different positions have different inference priorities; when the type
215 | walk finds a candidate at a higher priority position than existing
216 | candidates, it throws away the existing candidates and starts over
217 | with the higher-priority candidate. For example, a lone type variable
218 | has the highest priority, but a type variable found inside a return type
219 | has one of the lowest priorities.
220 |
221 | Priorities have two important limitations:
222 | first, they are defined ad-hoc, based on heuristics developed by
223 | observing bad type inferences and trying to fix them. Second, throwing away
224 | low-priority inferences is faster, but will miss some inferences
225 | compared to integrating all priorities in some way.
226 |
227 | #### Contravariant Candidates
228 |
229 | Certain candidates are inferred contravariantly, such as parameters of
230 | callbacks. This is a separate system from inference priorities;
231 | contravariant candidates are even higher priority.
232 |
233 | #### Reverse Mapped Types
234 |
235 | A reverse mapped type is a mapped type that is constructed during
236 | inference, and it requires information obtained from inference, but is
237 | not a central part of inference. A reverse mapped type is constructed when
238 | the target is a mapped type and the source is an object type. It
239 | allows a inference to apply to every member of an object type:
240 |
241 | ```ts
242 | type Box = { ref: T }
243 | type Boxed = { [K in keyof T]: Box }
244 | declare function unbox(boxed: Boxed): T;
245 | unbox({ a: { ref: 1 }, m: { ref: "1" } }) // returns { a: number, m: string }
246 | ```
247 |
248 | Reverse mapped types are normal types just like conditional types,
249 | index types, mapped types, etc. The difference is that they have no
250 | explicit syntax to construct them.
251 |
252 |
253 |
254 | [0]:
255 | [1]: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-6.html#strict-function-types
256 |
257 |
258 |
--------------------------------------------------------------------------------
/codebase/src/compiler/checker-relations.md:
--------------------------------------------------------------------------------
1 | # Relations
2 |
3 | There are 5 different type relations we have in the checker (in order of strictness, i.e. each is a subset of the next):
4 | - Identity
5 | - Strict subtyping
6 | - Subtyping
7 | - Assignability
8 | - Comparability
9 |
10 | We use those relations for different things in the checker, and in general, we have all those different relations because sometimes we wanna be more strict, and sometimes we don't.
11 |
12 | We use **assignability** for most things in the checker. For instance, we use it to check if an argument can be passed to a function, or if an expression can be assigned to a variable:
13 |
14 | ```ts
15 | declare let x: number;
16 | declare let y: string;
17 | y = x; // Error: Type 'number' is not assignable to type 'string'.
18 | ```
19 |
20 | Sometimes when we have a union type, we need to simplify it by a process called subtype reduction, i.e. remove components from the union which are subsumed by other components in the union. Subtype reduction is one of the situations when we use the **strict subtyping** relation.
21 |
22 | For example, when we're computing the type of an array literal from the types of its elements, we need to compare the type of each array element to one another, removing the types that are a subtype of another element type, i.e. subtype reduction. So to do this comparison between array element types, we use the strict subtyping relation, as seen in the following example:
23 |
24 | ```ts
25 | interface SomeObj {
26 | a: string;
27 | }
28 |
29 | interface SomeOtherObj {
30 | a: string;
31 | b?: number;
32 | }
33 |
34 | function yadda(x: SomeObj, y: SomeOtherObj) {
35 | x = y; // Ok, uses assignability relation
36 | y = x; // Ok, uses assignability relation
37 |
38 | return [x, y]; // Type inferred after subtype reduction is 'SomeObj[]',
39 | // because 'SomeOtherObj' is a strict subtype of 'SomeObj`.
40 | }
41 | ```
42 |
43 | The strict subtyping relation relates type `X` to type `Y` if `X` is a subtype of `Y`, but it does so in a way that avoids the problem that the regular (non-strict) subtyping relation has (and the assignability relation has as well) where two *different* types can be mutually related to one another[^1]. So we use the strict subtyping when we want to be sure that if `X` is a strict subtype of `Y`, then `Y` isn't a strict subtype of `X`, because otherwise we might end up having weird behavior, e.g. where the declaration order of a program changes the types the checker produces (see [this issue](https://github.com/microsoft/TypeScript/issues/52100), and [this PR](https://github.com/microsoft/TypeScript/pull/52282) for other possible weird consequences).
44 |
45 | [^1]: In mathematical terms, we want the strict subtyping relation to be antisymmetric.
46 |
47 | The **subtyping** relation also relates type `X` to type `Y` if `X` is a subtype of `Y`, but it has the issue mentioned above. For instance, `any` and `unknown` are both subtypes of each other. However, we use this relation despite the mentioned issue because we had the subtyping relation in the checker *before* we had the strict subtyping relation, so the subtyping relation is kept for backward compatibility. An example of where we use the subtyping relation is when resolving overloaded signatures. To see why we use subtyping for that purpose, consider the example of type `any`: something of type `any` is assignable to every other type, but `any` is not a subtype of every other type. So in the example:
48 |
49 | ```ts
50 | declare function myFunc(x: string): string;
51 | declare function myFunc(x: number): number;
52 | declare function myFunc(x: any): any;
53 |
54 | declare const a: any;
55 | myFunc(a); // After overload resolution, we infer `any`.
56 | ```
57 |
58 | When doing overload resolution, we try to match the argument type (`any`) to the parameter type of each overload signature using the subtype relation. Because `any` is not a subtype of `string` or `number`, we pick the last signature. If we used the assignability relation, we'd go match an `any` argument with the parameter type `string` on the first `myFunc` signature, and it would match, because `any` is assignable to `string`.
59 |
60 | > **Note:** something that can be confusing is how `any` has different behaviors depending on the relation being used to compare it, and how it differs from `unknown`. Basically, `any` is special because it is assignable to every type, but `any` is not a subtype of every type. And every type is assignable to `any`, and every type is a subtype of `any`. So `any` has this special behavior during assignability where it is assignable to **any**thing.
61 | `unknown`, like `any`, is also a supertype of every other type. However, `unknown` doesn't have `any`'s special assignability behavior: everything is assignable to `unknown`, but `unknown` is not assignable to everything.
62 |
63 | Another relation we have is **comparability**. We use comparability to check if two types possibly overlap and values of those types can possibly be compared to one another. For example:
64 |
65 | ```ts
66 | type Color = "red" | "blue" | "green" | "orange";
67 | type Fruit = "apple" | "banana" | "orange";
68 | type Shape = "square" | "rectangle";
69 |
70 | function myFoo(color: Color, fruit: Fruit, shape: Shape) {
71 | color = fruit; // Error: Type 'Fruit' is not assignable to type 'Color'.
72 | fruit = color; // Error: Type 'Color' is not assignable to type 'Fruit'.
73 | if (color === fruit) { // Ok, because 'Fruit' and 'Color' are comparable.
74 | ...
75 | }
76 | if (color === shape) { // Error: This comparison appears to be unintentional because the types 'Color' and 'Shape' have no overlap.
77 | ...
78 | }
79 | }
80 | ```
81 | The types `Color` and `Fruit`, despite not being assignable to each other, are comparable, because if we think of types as sets, they have values in common (in this case, value `"orange"`). However, types `Color` and `Shape` are not comparable, so the checker will complain if you try to compare values of those two types.
82 |
83 | As for the **identity** relation, it means to be used as its name implies: to check if two types are **identical**. We use that one more rarely in the checker. One example is when you declare the same `var` multiple times (which is allowed), the checker checks that the declared types are identical among all of the declarations.
84 |
85 | Another usage of identity is in inference. When inferring from one type into another, we get rid of the parts of both types that are identical. For example, when inferring from one union to another union, e.g. from `boolean | string | number` to `T | string | number`, we get rid of the identical types on both sides (`string` and `number`) to end up inferring from `boolean` into `T`.
86 | Yet another example is when checking assignability of two instantiations of the same invariant generic type: two instantiations are still related if their type arguments are identical.
87 |
88 | > **Implementation note:** We try to make checking the above relations fast in the checker's implementation, and we use different strategies to achieve that.
89 | As an example, consider the identity relation. Most of the time it is used for object types, and we try to make it quick to check that by interning that information.
90 | For example, instantiations of the same type with the same arguments produce the same type, so it's fast to check that the instantiated types are identical.
91 | However, we don't intern all identical object types: anonymous object literal types are not interned. So they have distinct types, but they are identical, so we end up having to do a more expensive check to see that they're identical.
92 |
93 | If you want to see more about the implementation and use of those relations in the checker, the entry point to using all those relations is the function `isTypeRelatedTo`.
--------------------------------------------------------------------------------
/codebase/src/compiler/checker-widening-narrowing.md:
--------------------------------------------------------------------------------
1 | # Widening and Narrowing in Typescript
2 |
3 | Typescript has a number of related concepts in which a type gets
4 | treated temporarily as a similar type. Most of these concepts are
5 | internal-only. None of them are documented very well. For the internal
6 | concepts, we expect nobody needs to know about them to use the
7 | language. For the external concepts, we hope that they work well
8 | enough that most people *still* don't need to think about them. This
9 | document explains them all, aiming to help two audiences: (1) advanced
10 | users of Typescript who *do* need to understand the quirks of the
11 | language (2) contributors to the Typescript compiler.
12 |
13 | The concepts covered in this document are as follows:
14 |
15 | 1. Widening: treat an internal type as a normal one.
16 | 2. Literal widening: treat a literal type as a primitive one.
17 | 3. Narrowing: remove constituents from a union type.
18 | 4. Instanceof narrowing: treat a type as a subclass.
19 | 5. Apparent type: treat a non-object type as an object type.
20 |
21 | ## Widening
22 |
23 | Widening is the simplest operation of the bunch. The types `null` and
24 | `undefined` are converted to `any`. This happens
25 | recursively in object types, union types, and array types (including
26 | tuples).
27 |
28 | Why widening? Well, historically, `null` and `undefined` were internal
29 | types that needed to be converted to `any` for downstream consumers
30 | and for display. With `--strictNullChecks`, widening doesn't happen
31 | any more. But without it, widening happens a lot, generally when obtaining
32 | a type from another object. Here are some examples:
33 |
34 | ```ts
35 | // @strict: false
36 | let x = null;
37 | ```
38 |
39 | Here, `null` has the type `null`, but `x` has the type `any` because
40 | of widening on assignment. `undefined` works the same way. However,
41 | with `--strict`, `null` is preserved, so no widening will happen.
42 |
43 | ## Literal widening
44 |
45 | Literal widening is significantly more complex than "classic"
46 | widening. Basically, when literal widening happens, a literal type
47 | like `"foo"` or `SomeEnum.Member` gets treated as its base type:
48 | `string` or `SomeEnum`, respectively. The places where literals widen,
49 | however, cause the behaviour to be hard to understand. Literal
50 | widening is described fully
51 | [at the literal widening PR](https://github.com/Microsoft/TypeScript/pull/10676)
52 | and
53 | [its followup](https://github.com/Microsoft/TypeScript/pull/11126).
54 |
55 | ### When does literal widening happen?
56 |
57 | There are two key points to understand about literal widening.
58 |
59 | 1. Literal widening only happens to literal types that originate from
60 | expressions. These are called *fresh* literal types.
61 | 2. Literal widening happens whenever a fresh literal type reaches a
62 | "mutable" location.
63 |
64 | For example,
65 |
66 | ```ts
67 | const one = 1; // 'one' has type: 1
68 | let num = 1; // 'num' has type: number
69 | ```
70 |
71 | Let's break the first line down:
72 |
73 | 1. `1` has the fresh literal type `1`.
74 | 2. `1` is assigned to `const one`, so `one: 1`. But the type `1` is still
75 | fresh! Remember that for later.
76 |
77 | Meanwhile, on the second line:
78 |
79 | 1. `1` has the fresh literal type `1`.
80 | 2. `1` is assigned to `let num`, a mutable location, so `num: number`.
81 |
82 | Here's where it gets confusing. Look at this:
83 |
84 | ```ts
85 | const one = 1;
86 | let wat = one; // 'wat' has type: number
87 | ```
88 |
89 | The first two steps are the same as the first example. The third step
90 |
91 | 1. `1` has the fresh literal type `1`.
92 | 2. `1` is assigned to `const one`, so `one: 1`.
93 | 3. `one` is assigned to `wat`, a mutable location, so `wat: number`.
94 |
95 | This is pretty confusing! The fresh literal type `1` makes its way
96 | *through* the assignment to `one` down to the assignment to `wat`. But
97 | if you think about it, this is what you want in a real program:
98 |
99 | ```ts
100 | const start = 1001;
101 | const max = 100000;
102 | // many (thousands?) of lines later ...
103 | for (let i = start; i < max; i = i + 1) {
104 | // did I just write a for loop?
105 | // is this a C program?
106 | }
107 | ```
108 |
109 | If the type of `i` were `1001` then you couldn't write a for loop based
110 | on constants.
111 |
112 | There are other places that widen besides assignment. Basically it's
113 | anywhere that mutation could happen:
114 |
115 | ```ts
116 | const nums = [1, 2, 3]; // 'nums' has type: number[]
117 | nums[0] = 101; // because Javascript arrays are always mutable
118 |
119 | const doom = { e: 1, m: 1 }
120 | doom.e = 2 // Mutable objects! We're doomed!
121 |
122 | // Dooomed!
123 | // Doomed!
124 | // -gasp- Dooooooooooooooooooooooooooooooooo-
125 | ```
126 |
127 | ### What literal types widen?
128 |
129 | * Number literal types like `1` widen to `number`.
130 | * String literal types like `'hi'` widen to `string`.
131 | * Boolean literal types like `true` widen to `boolean`.
132 | * Enum members widen to their containing enum.
133 |
134 | An example of the last is:
135 |
136 | ```ts
137 | enum State {
138 | Start,
139 | Expression,
140 | Term,
141 | End
142 | }
143 | const start = State.Start;
144 | let state = start;
145 | let ch = '';
146 | while (ch = nextChar()) {
147 | switch (state) {
148 | // ... imagine your favourite tokeniser here
149 | }
150 | }
151 | ```
152 |
153 | ## Narrowing
154 |
155 | Narrowing is essentially the removal of types from a union. It's
156 | happening all the time as you write code, especially if you use
157 | `--strictNullChecks`. To understand narrowing, you first need to
158 | understand the difference between "declared type" and "computed type".
159 |
160 | The declared type of a variable is the one it's declared with. For
161 | `let x: number | undefined`, that's `number | undefined`. The computed
162 | type of a variable is the type of the variable as it's used in
163 | context. Here's an example:
164 |
165 | ```ts
166 | // @strict: true
167 | type Thing = { name: 'one' | 'two' };
168 | function process(origin: Thing, extra?: Thing | undefined): void {
169 | preprocess(origin, extra);
170 | if (extra) {
171 | console.log(extra.name);
172 | if (extra.name === 'one') {
173 | // ...
174 | ```
175 |
176 | `extra`'s declared type is `Thing | undefined`, since it's an optional
177 | parameter. However, its computed type varies based on context. On the
178 | first line, in `preprocess(origin, extra)`, its computed type is still
179 | `Thing | undefined`. However, inside the `if (extra)` block, `extra`'s
180 | computed type is now just `Thing` because it can't possibly be
181 | `undefined` due to the `if (extra)` check. Narrowing has removed
182 | `undefined` from its type.
183 |
184 | Similarly, the declared type of `extra.name` is `'one' | 'two'`, but
185 | inside the true branch of `if (extra.name === 'one')`, its computed
186 | type is just `'one'`.
187 |
188 | Narrowing mostly commonly removes all but one type from a union, but
189 | doesn't necessarily need to:
190 |
191 | ```ts
192 | type Type = Anonymous | Class | Interface
193 | function f(thing: string | number | boolean | object) {
194 | if (typeof thing === 'string' || typeof thing === 'number') {
195 | return lookup[thing];
196 | }
197 | else if (typeof thing === 'boolean' && thing) {
198 | return globalCachedThing;
199 | }
200 | else {
201 | return thing;
202 | }
203 | }
204 | ```
205 |
206 | Here, in the first if-block, `thing` narrows to `string | number` because
207 | the check allows it to be either string or number.
208 |
209 | ## Instanceof Narrowing
210 |
211 | Instanceof narrowing looks similar to normal narrowing, and
212 | behaves similarly, but its rules are somewhat different. It only
213 | applies to certain `instanceof` checks and type predicates.
214 |
215 | Here's a use of `instanceof` that follows the normal narrowing rules:
216 |
217 | ```ts
218 | class C { c: any }
219 | function f(x: C | string) {
220 | if (x instanceof C) {
221 | // x is C here
222 | }
223 | else {
224 | // x is string here
225 | }
226 | }
227 | ```
228 |
229 | So far this follows the normal narrowing rules. But `instanceof`
230 | applies to subclasses too:
231 |
232 | ```ts
233 | class D extends C { d: any }
234 | function f(x: C) {
235 | if (x instanceof D) {
236 | // x is D here
237 | }
238 | else {
239 | // x is still just C here
240 | }
241 | }
242 | ```
243 |
244 | Unlike narrowing, `instanceof` narrowing doesn't remove any types to
245 | get `x`'s computed type. It just notices that `D` is a subclass of `C`
246 | and changes the computed type to `D` inside the `if (x instanceof D)`
247 | block. In the `else` block `x` is still `C`.
248 |
249 | If you mess up the class relationship, the compiler does its best
250 | to make sense of things:
251 |
252 | ```ts
253 | class E { e: any } // doesn't extend C!
254 | function f(x: C) {
255 | if (x instanceof E) {
256 | // x is C & E here
257 | }
258 | else {
259 | // x is still just C here
260 | }
261 | }
262 | ```
263 |
264 | The compiler thinks that something of type `C` can't also be
265 | `instanceof E`, but just in case, it sets the computed type of `x` to
266 | `C & E`, so that you can use the properties of `E` in the block
267 | — just be aware that the block will probably never execute!
268 |
269 | ### Type predicates
270 |
271 | Type predicates follow the same rules as `instanceof` when narrowing,
272 | and are just as subject to misuse. So this example is equivalent to
273 | the previous wonky one:
274 |
275 | ```ts
276 | function isE(e: any): e is E {
277 | return e.e;
278 | }
279 | function f(x: C) {
280 | if (isE(x)) {
281 | // x is C & E here
282 | }
283 | else {
284 | // nope, still just C
285 | }
286 | }
287 | ```
288 |
289 | ## Apparent Type
290 |
291 | In some situations you need to get the properties on a variable, even
292 | when it technically doesn't have properties. One example is primitives:
293 |
294 | ```ts
295 | let n = 12
296 | let s = n.toFixed()
297 | ```
298 |
299 | `12` doesn't technically have properties; `Number` does. In order to
300 | map `number` to `Number`, we define `Number` as the *apparent type* of
301 | `number`. Whenever the compiler needs to get properties of some type,
302 | it asks for the apparent type of that type first. This applies to
303 | other non-object types like type parameters:
304 |
305 | ```ts
306 | interface Node {
307 | parent: Node;
308 | pos: number;
309 | kind: number;
310 | }
311 | function setParent(node: T, parent: Node): T {
312 | node.parent = parent;
313 | return node;
314 | }
315 | ```
316 |
317 | `T` is a type parameter, which is just a placeholder. But its
318 | constraint is `Node`, so when the compiler checks `node.parent`, it
319 | gets the apparent type of `T`, which is `Node`. Then it sees that
320 | `Node` has a `parent` property.
321 |
--------------------------------------------------------------------------------
/codebase/src/compiler/checker.md:
--------------------------------------------------------------------------------
1 | # Checker
2 |
3 | Ok, yeah, so it's a 40k LOC file. Why 40k lines in one file? Well there's a few main arguments:
4 |
5 | - All of the checker is in one place.
6 | - Save memory by making it a global, to quote a comment in the parser:
7 |
8 | > ```
9 | > // Implement the parser as a singleton module. We do this for perf reasons because creating parser instances
10 | > // can actually be expensive enough to impact us on projects with many source files.
11 | > ```
12 |
13 | Lots of these functions need to know a lot about each other, the top of the function `createTypeChecker` has a set
14 | of variables which are global within all of these functions and are liberally accessed.
15 |
16 | Switching to different files means probably making [god objects][god], and the checker needs to be extremely fast.
17 | We want to avoid additional calls for ambient context. There are architectural patterns for this, but it's better
18 | to assume good faith that they've been explored already (8 years down the line now.)
19 |
20 | [god]: https://en.wikipedia.org/wiki/God_object
21 |
22 | Anyway, better to get started somewhere. I [asked online](https://twitter.com/orta/status/1148335807780007939)
23 | about how people would try to study a file like this and I think one of the best paths is by following a
24 | particular story as a file gets checked.
25 |
26 | ## An entry-point
27 |
28 | The likely entry point for type checking is via a Program. The program has a memoized typechecker created in
29 | [`getDiagnosticsProducingTypeChecker`][0] which creates a type checker.
30 |
31 | The initial start of type checking starts with [`getDiagnosticsWorker`][1], worker in this case isn't a threading
32 | term I believe ( at least I can't find anything like that in the code ) - it is set up to listen for diagnostic
33 | results (e.g. warns/fails) and then triggers [`checkSourceFileWorker`][2].
34 |
35 | This function starts at the root `Node` of any TS/JS file node tree: `SourceFile`. It will then have to recurse
36 | through all of the [Syntax Tree][ast] nodes in it's tree.
37 |
38 | It doesn't start with a single recursive function though, it starts by looking through the SourceFile's
39 | [`statements`][4] and through each one of those to get all the nodes. For example:
40 |
41 | ```ts
42 | // Statement 1
43 | const hi = () => "Hello";
44 |
45 | // Statement 2
46 | console.log(hi());
47 | ```
48 |
49 | Which looks a bit like:
50 |
51 | ```sh
52 | SourceFile
53 | statements:
54 |
55 | - VariableStatement
56 | - declarationList: VariableDeclarationList # (because any const can have many declarations in a row... )
57 | - variables: VariableStatement
58 | - etc
59 |
60 | - ExpressionStatement
61 | - expression: CallExpression # outer console.log
62 | - expression: PropertyAccessExpression
63 | - etc
64 | - arguments: CallExpression
65 | - etc
66 | ```
67 |
68 | [See AST Explorer](https://astexplorer.net/#/gist/80c981c87035a45a753c0ee5c983ecc9/6276351b153f4dac9811bf7214c9b236ae420c7e)
69 |
70 | Each node has a different variable to work with (so you can't just say
71 | `if node.children { node.children.foreach(lookAtNode) }` ) but instead you need to examine each node individually.
72 |
73 | ## Checking a Statement
74 |
75 | Initially the meat of the work starts in [`checkSourceElementWorker`][6] which has a `switch` statement that
76 | contains all legitimate nodes which can start a statement. Each node in the tree then does it's checking.
77 |
78 | Let's try get a really early error, with this bad code:
79 |
80 | ```ts
81 | // A return statement shouldn't exist here in strict mode (or any mode?)
82 | return;
83 | ~~~~~~
84 | ```
85 |
86 | It goes into [`checkReturnStatement`][6] which uses [`getContainingFunction`][7] to determine if the `return`
87 | lives inside a [`function-like`][8] node ( e.g. `MethodSignature`, `CallSignature`, `JSDocSignature`,
88 | `ConstructSignature`, `IndexSignature`, `FunctionType`, `JSDocFunctionType`, `ConstructorType`).
89 |
90 | Because the parent of the `return` statement is the root (`parent: SourceFileObject`) then it's going to fail.
91 | This triggers [`grammarErrorOnFirstToken`][9] which will raise the error:
92 | `A 'return' statement can only be used within a function body.ts(1108)` and declare the error underline to the
93 | first token inside that node.
94 |
95 | ## Checking Type Equality
96 |
97 | ```ts
98 | const myString = "Hello World";
99 | const myInt = 123;
100 | // Error: This condition will always return 'false' since the types '123' and '"Hello World"' have no overlap.
101 | if (myInt === myString) {
102 | // Do something
103 | }
104 | ```
105 |
106 | To get to this error message:
107 |
108 | - [`checkSourceElementWorker`][6] loops through the 3 statements in the `SourceFile`
109 | - In the third, it goes through:
110 | - [`checkIfStatement`][13]
111 | - [`checkTruthinessExpression`][11]
112 | - [`checkExpression`][12]
113 | - [`checkBinaryLikeExpression`][14] where it fails.
114 | - The fail comes from inside [`isTypeRelatedTo`][15] which has a set of heuristics for whether the types are the
115 | same ([`isSimpleTypeRelatedTo`][16] uses cached data in NodeLinks, and [`checkTypeRelatedTo`][17] dives deeper)
116 | and if not then. It will raise.
117 |
118 | ### Caching Data While Checking
119 |
120 | Note there are two ways in which TypeScript is used, as a server and as a one-off compiler. In a server, we want
121 | to re-use as much as possible between API requests, and so the Node tree is treated as immutable data until there
122 | is a new AST.
123 |
124 | This gets tricky inside the Type Checker, which for speed reasons needs to cache data somewhere. The solution to
125 | this is the [`NodeLinks`][3] property on a Node. The Type Checker fills this up during the run and re-uses it,
126 | then it is discarded next time you re-run the checker.
127 |
128 | ### Type Flags
129 |
130 | Because TypeScript is a [structural type system][20], every type can reasonably be compared with every other type.
131 | One of the main ways in which TypeScript keeps track of the underlying data-model is via the
132 | [`enum TypeFlags`][19]. Accessed via `.flags` on any node, it is a value which is used via bitmasking to let you
133 | know what data it represents.
134 |
135 | If you wanted to check for whether the type is a union:
136 |
137 | ```ts
138 | if (target.flags & TypeFlags.Union && source.flags & TypeFlags.Object) {
139 | // is a union object
140 | }
141 | ```
142 |
143 | When running the compiler in debug mode, you can see a string version of this via `target.__debugFlags`.
144 |
145 | ### Type Comparison
146 |
147 | The entry point for comparing two types happens in [`checkTypeRelatedTo`][17]. This function is mostly about
148 | handling the diagnostic results from any checking though and doesn't do the work. The honour of that goes to
149 | [`isRelatedTo`][18] which:
150 |
151 | - Figures out what the source and target types should be (based on freshness (a literal which was created in an
152 | expression), whether it is substituted () or simplifiable (a type which depends first on resolving another
153 | type))
154 |
155 | - First, check if they're identical via [`isIdenticalTo`][21]. The check for most objects occurs in
156 | [`recursiveTypeRelatedTo`][22], unions and intersections have a check that compares each value in
157 | [`eachTypeRelatedToSomeType`][23] which eventually calls [`recursiveTypeRelatedTo`][22] for each item in the
158 | type.
159 |
160 | - The heavy lifting of the comparison depending on what flags are set on the node is done in
161 | [`structuredTypeRelatedTo`][23]. Where it picks off one by one different possible combinations for matching and
162 | returns early as soon as possible.
163 |
164 | A lot of the functions related to type checking return a [`Ternary`][24], which an enum with three states, true,
165 | false and maybe. This gives the checker the chance to admit that it probably can't figure out whether a match is
166 | true currently (maybe it hit the 100 depth limit for example) and potentially could be figured out coming in from
167 | a different resolution.
168 |
169 | TODO: what are substituted types?
170 |
171 | ## Debugging Advice
172 |
173 | - If you want to find a diagnostic in the codebase, search for `diag(WXZY` e.g
174 | ``, you'll find `src/compiler/diagnosticInformationMap.generated.ts` has it being referenced by a key. Search
175 | for that key.
176 |
177 | - If you're working from an error and want to see the path it took to get there, you can add a breakpoint in
178 | [`createFileDiagnostic`][10] which should get called for all diagnostic errors.
179 |
180 |
181 | [0]: https://github.com/microsoft/TypeScript/blob/db9e0079/src/compiler/program.ts#L1926
182 | [0]:
183 | [1]: https://github.com/microsoft/TypeScript/blob/db9e0079/src/compiler/checker.ts#L40626
184 | [1]:
185 | [2]: https://github.com/microsoft/TypeScript/blob/db9e0079/src/compiler/checker.ts#L40546
186 | [2]:
187 | [3]: https://github.com/microsoft/TypeScript/blob/db9e0079//src/compiler/types.ts#L5091
188 | [3]:
189 | [4]: GLOSSARY.md#statements
190 | [ast]: GLOSSARY.md#statements
191 | [5]: https://github.com/microsoft/TypeScript/blob/db9e0079/src/compiler/checker.ts#L40194
192 | [5]:
193 | [6]: https://github.com/microsoft/TypeScript/blob/db9e0079/src/compiler/checker.ts#L38138
194 | [6]:
195 | [7]: https://github.com/microsoft/TypeScript/blob/db9e0079/src/compiler/checker.ts
196 | [7]:
197 | [8]: https://github.com/microsoft/TypeScript/blob/db9e0079/src/compiler/utilities.ts
198 | [8]:
199 | [9]: https://github.com/microsoft/TypeScript/blob/db9e0079/src/compiler/checker.ts#L43738
200 | [9]:
201 | [10]: https://github.com/microsoft/TypeScript/blob/db9e0079/src/compiler/utilities.ts#L5960
202 | [10]:
203 | [11]: https://github.com/microsoft/TypeScript/blob/db9e0079/src/compiler/checker.ts#L37216
204 | [11]:
205 | [12]: https://github.com/microsoft/TypeScript/blob/db9e0079/src/compiler/checker.ts#L17221
206 | [12]:
207 | [13]: https://github.com/microsoft/TypeScript/blob/db9e0079/src/compiler/checker.ts#L37076
208 | [13]:
209 | [14]: https://github.com/microsoft/TypeScript/blob/db9e0079/src/compiler/checker.ts#L33081
210 | [14]:
211 | [15]: https://github.com/microsoft/TypeScript/blob/db9e0079/src/compiler/checker.ts#L17842
212 | [15]:
213 | [16]: https://github.com/microsoft/TypeScript/blob/db9e0079/src/compiler/checker.ts#L17805
214 | [16]:
215 | [17]: https://github.com/microsoft/TypeScript/blob/db9e0079/src/compiler/checker.ts#L17063
216 | [17]:
217 | [17]: https://github.com/microsoft/TypeScript/blob/db9e0079/src/compiler/checker.ts#L18240
218 | [17]:
219 | [19]: https://github.com/microsoft/TypeScript/blob/db9e0079/src/compiler/types.ts#L5120
220 | [19]:
221 | [20]: GLOSSARY.md#structural-type-system
222 | [21]: https://github.com/microsoft/TypeScript/blob/db9e0079/src/compiler/checker.ts#L18479
223 | [21]:
224 | [22]: https://github.com/microsoft/TypeScript/blob/db9e0079/src/compiler/checker.ts#L18758
225 | [22]:
226 | [22]: https://github.com/microsoft/TypeScript/blob/db9e0079/src/compiler/checker.ts#L18589
227 | [22]:
228 | [23]: https://github.com/microsoft/TypeScript/blob/db9e0079/src/compiler/checker.ts#L18872
229 | [23]:
230 | [24]: https://github.com/microsoft/TypeScript/blob/eb430f27/src/compiler/types.ts#L6097
231 | [24]:
232 |
233 |
--------------------------------------------------------------------------------
/codebase/src/compiler/emitter.md:
--------------------------------------------------------------------------------
1 | ## Emitter
2 |
3 | The emitter is a tree based syntax emitter. It works by going through the TypeScript AST for a program and
4 | emitting source code as it is pipelined.
5 |
6 | The emitter itself is "dumb" in the sense that it doesn't contain logic outside of printing whatever AST it is
7 | given. So, it's possible that a bug in emission is actually that the AST isn't set up the way that you'd like it.
8 |
9 | ### Outfile
10 |
11 | Creating a single file which represents many is done by creating a `SyntaxKind.Bundle`. Printing happens in
12 | [`function writeBundle(`][0]. There are `prepends` which I don't understand, and then each sourcefile is is
13 | printed.
14 |
15 | ### Printer
16 |
17 | The printer is a part of the emitter, you create one with [`createPrinter`][1], then start calling [`print`][2]
18 | with an AST node on it. This adds the node via a [pipeline][3]:
19 |
20 | ```ts
21 | const enum PipelinePhase {
22 | Notification,
23 | Substitution,
24 | Comments,
25 | SourceMaps,
26 | Emit,
27 | }
28 | ```
29 |
30 | With the word to start emitting through the AST in [`pipelineEmitWithHint`][4]. There is a hint option which can
31 | be used to force the emit type.
32 |
33 | ## Post Processing via Transformers
34 |
35 | The process of changing your AST into the expected JS or TS happens the emitter compiler transformers. There is a
36 | full step
37 |
38 | Emitting a declaration file is a multi-step process. It goes through the above emitter of its AST, but then _also_
39 | goes through a
40 |
41 |
42 | [0]: https://github.com/microsoft/TypeScript/blob/db9e0079/src/compiler/emitter.ts#L1041
43 | [0]:
44 | [1]: https://github.com/microsoft/TypeScript/blob/db9e0079/src/compiler/emitter.ts#L852
45 | [1]:
46 | [2]: https://github.com/microsoft/TypeScript/blob/db9e0079/src/compiler/emitter.ts#L1129
47 | [2]:
48 | [3]: https://github.com/microsoft/TypeScript/blob/db9e0079/src/compiler/emitter.ts#L844
49 | [3]:
50 | [3]: https://github.com/microsoft/TypeScript/blob/db9e0079/src/compiler/emitter.ts#L1270
51 | [3]:
52 |
53 |
--------------------------------------------------------------------------------
/codebase/src/compiler/faq.md:
--------------------------------------------------------------------------------
1 | # Frequently Asked Questions
2 |
3 | ## How can I find out if a type is `number[]`?
4 |
5 | ```ts
6 | getElementTypeOfArrayType(t) === numberType
7 | ```
8 |
9 | `getElementTypeOfArrayType` returns undefined if `t` is not an array type.
10 | Use `isArrayType` or `isArrayLikeType` if that's all you need to know.
11 |
12 | ## How can I delete nodes in a transformer?
13 |
14 | Probably you return `undefined` instead of a new or existin node, but look at src/compiler/transformers/ts.ts.
15 | Deleting type annotations is its main job.
16 |
17 |
--------------------------------------------------------------------------------
/codebase/src/compiler/parser.md:
--------------------------------------------------------------------------------
1 |
2 | [0]: https://github.com/microsoft/TypeScript/blob/db9e0079/src/compiler/program.ts#L1926# Parser
3 |
4 | At a measly 8k lines long, the Parser is responsible for controlling a scanner (or two) and turning the output
5 | tokens from the scanner into an AST as the canonical representation of the source file.
6 |
7 | ## JSDoc
8 |
9 | ## Context
10 |
11 | Because the parser itself is effectively a state machine which creates nodes from scanning text there is some
12 | reasonable dancing
13 |
14 |
15 |
16 | [0]:
17 | [4]: GLOSSARY.md#statements
18 |
19 |
20 |
21 | `
22 |
--------------------------------------------------------------------------------
/codebase/src/compiler/scanner.md:
--------------------------------------------------------------------------------
1 | # Scanner
2 |
3 | One of the smallest parts of the compiler's critical path to AST then type-checking. It exists to create a stream
4 | of syntax tokens for use by another object. The scanner gets most of its usage via a [parser][0] instance.
5 |
6 | ## Overview
7 |
8 | You create a Scanner instance via [`createScanner`][1], there are two main modes of scanning: Standard and JSX.
9 | Then there are specific functions for scanning inside JSDoc comments.
10 |
11 | First you set the text of a scanner to be your JS source code via [`setText`][2], this takes the source code and
12 | an optional start and end range in which you want to scan. This range is an important part of what keeps
13 | TypeScript's server mode fast via [incremental parsing][3].
14 |
15 | At a high level, the scanner works by a having another object call [`scanner.scan`][4] this:
16 |
17 | - Pulls out the character at the current position (`pos`) in the text
18 | - Runs a very big switch statement against known characters which start syntax
19 | - Then move look forwards till the end of that list of chars to decode if it's what we think it is. here's an
20 | example of what happens when [the character found][5] is a `!`:
21 |
22 | ```ts
23 | case CharacterCodes.exclamation:
24 | // Look to see if it's "!="
25 | if (text.charCodeAt(pos + 1) === CharacterCodes.equals) {
26 | // Also check if it's "!=="
27 | if (text.charCodeAt(pos + 2) === CharacterCodes.equals) {
28 | // for !== move the position forwards to the end of the symbol
29 | // then set the token
30 | return pos += 3, token = SyntaxKind.ExclamationEqualsEqualsToken;
31 | }
32 | // Move it two, set the token
33 | return pos += 2, token = SyntaxKind.ExclamationEqualsToken;
34 | }
35 |
36 | // Move forwards one character and set the token
37 | pos++;
38 | return token = SyntaxKind.ExclamationToken;
39 | ```
40 |
41 | - A `SyntaxKind` is returned from [`scan`][4] and it's up to the scanner owner to do work with those tokens. The
42 | scanner keeps track of a few useful values for that:
43 |
44 | - `getStartPos` - where the token was started including preceding whitespace
45 | - `getTextPos` - the end position of the current token
46 | - `getTokenText` - the text between the token start and end
47 | - `getTokenValue` - some syntax contains a value which can be represented as a string, a good example is
48 | literally a string. The `"` or `'` are not included in the value.
49 |
50 |
51 | ## Full Start/Token Start
52 |
53 | Tokens themselves have what we call a "full start" and a "token start". The "token start" is the more natural version, which is the position in the file where the text of a token begins. The "full start" is the point at which the scanner began scanning since the last significant token. When concerned with trivia, we are often more concerned with the full start.
54 |
55 | Function | Description
56 | ---------|------------
57 | `ts.Node.getStart` | Gets the position in text where the first token of a node started.
58 | `ts.Node.getFullStart` | Gets the position of the "full start" of the first token owned by the node.
59 |
60 |
61 | ## Trivia
62 |
63 | When creating a scanner you get to choose whether whitespace should be returned in the stream of tokens. This is
64 | nearly always off, but it is used inside the [formatter][6] and for syntax highlighting via the TSServer via a
65 | [classifier][7].
66 |
67 | Syntax trivia represent the parts of the source text that are largely insignificant for normal understanding of the code, such as whitespace, comments, and even conflict markers.
68 |
69 | Because trivia are not part of the normal language syntax (barring ECMAScript ASI rules) and can appear anywhere between any two tokens, they are not included in the syntax tree. Yet, because they are important when implementing a feature like refactoring and to maintain full fidelity with the source text, they are still accessible through our APIs on demand.
70 |
71 | Because the `EndOfFileToken` can have nothing following it (neither token nor trivia), all trivia naturally precedes some non-trivia token, and resides between that token's "full start" and the "token start"
72 |
73 | It is a convenient notion to state that a comment "belongs" to a `Node` in a more natural manner though. For instance, it might be visually clear that the `genie` function declaration owns the last two comments in the following example:
74 |
75 | ```TypeScript
76 | var x = 10; // This is x.
77 |
78 | /**
79 | * Postcondition: Grants all three wishes.
80 | */
81 | function genie([wish1, wish2, wish3]: [Wish, Wish, Wish]) {
82 | while (true) {
83 | }
84 | } // End function
85 | ```
86 |
87 | This is despite the fact that the function declaration's full start occurs directly after `var x = 10;`.
88 |
89 | We follow [Roslyn's notion of trivia ownership](https://github.com/dotnet/roslyn/wiki/Roslyn%20Overview#syntax-trivia) for comment ownership. In general, a token owns any trivia after it on the same line up to the next token. Any comment after that line is associated with the following token. The first token in the source file gets all the initial trivia, and the last sequence of trivia in the file is tacked onto the end-of-file token, which otherwise has zero width.
90 |
91 | For most basic uses, comments are the "interesting" trivia. The comments that belong to a Node which can be fetched through the following functions:
92 |
93 | Function | Description
94 | ---------|------------
95 | `ts.getLeadingCommentRanges` | Given the source text and position within that text, returns ranges of comments between the first line break following the given position and the token itself (probably most useful with `ts.Node.getFullStart`).
96 | `ts.getTrailingCommentRanges` | Given the source text and position within that text, returns ranges of comments until the first line break following the given position (probably most useful with `ts.Node.getEnd`).
97 |
98 | As an example, imagine this portion of a source file:
99 |
100 | ```TypeScript
101 | debugger;/*hello*/
102 | //bye
103 | /*hi*/ function
104 | ```
105 |
106 | The full start for the `function` keyword begins at the `/*hello*/` comment, but `getLeadingCommentRanges` will only return the last 2 comments:
107 |
108 | ```
109 | d e b u g g e r ; / * h e l l o * / _ _ _ _ _ [CR] [NL] _ _ _ _ / / b y e [CR] [NL] _ _ / * h i * / _ _ _ _ f u n c t i o n
110 | ↑ ↑ ↑ ↑ ↑
111 | full start look for first comment second comment token start
112 | leading comments
113 | starting here
114 | ```
115 |
116 | Appropriately, calling `getTrailingCommentRanges` on the end of the debugger statement will extract the `/*hello*/` comment.
117 |
118 | In the event that you are concerned with richer information of the token stream, `createScanner` also has a `skipTrivia` flag which you can set to `false`, and use `setText`/`setTextPos` to scan at different points in a file.
119 |
120 |
121 | ## JSX
122 |
123 | Some of the more complicated aspects of JSX support is mostly handled back in [the parser][0], however JSX support
124 | in the scanner [uses specific syntax tokens][8].
125 |
126 | ## Flags
127 |
128 | One way for the scanner to keep track of scan issues, or internal state is [via `TokenFlags`][9]. Any example of
129 | this is in scanning a number. TypeScript supports underscores in numbers `100_000`, when scanning a number literal
130 | if it detects a `CharacterCodes._` then the flag `TokenFlags.ContainsSeparator` is set and later on that is used
131 | to ensure the `tokenValue` is set correctly.
132 |
133 | ## Rescanning
134 |
135 | Because the scanner is only interested in passing out tokens as it sees them, it doesn't really have a memory of
136 | previous tokens. This means that occasionally the controlling object will need to rewind and re-run the scanner
137 | with a different type of context. This is called rescanning.
138 |
139 | ## Example code
140 |
141 | [Here's a scanner playground](https://5d39df23407c626e65aee7ef--ts-scanner-tokens.netlify.com) - adding TypeScript
142 | will show you the tokens generated by a single scanner. It's worth noting that this doesn't represent that
143 | _actual_ results of the scanner when using TypeScript, because the parser controls re-scanning and this playground
144 | doesn't do that.
145 |
146 |
147 | [0]: ./parser.md
148 | [1]: https://github.com/microsoft/TypeScript/blob/db9e0079/src/compiler/scanner.ts#L929
149 | [1]:
150 | [2]: https://github.com/microsoft/TypeScript/blob/db9e0079/src/compiler/scanner.ts#L2551
151 | [2]:
152 | [3]: GLOSSARY.md#incremental-parsing
153 | [4]: https://github.com/microsoft/TypeScript/blob/db9e0079/src/compiler/scanner.ts#L1609
154 | [4]:
155 | [5]: https://github.com/microsoft/TypeScript/blob/db9e0079/src/compiler/scanner.ts#L1681
156 | [5]:
157 | [6]: ./formatter.md
158 | [7]: https://github.com/microsoft/TypeScript/blob/db9e0079/src/services/classifier.ts#L3
159 | [7]:
160 | [8]: https://github.com/microsoft/TypeScript/blob/db9e0079/src/compiler/types.ts#L709
161 | [8]:
162 | [9]: https://github.com/microsoft/TypeScript/blob/db9e0079/src/compiler/types.ts#L2159
163 | [9]:
164 |
165 |
--------------------------------------------------------------------------------
/codebase/src/compiler/services.md:
--------------------------------------------------------------------------------
1 | ## Services
2 |
3 | `services` is effectively the place where all the IDE and TS meet. It it a series of files which power the
4 | LSP-like TSServer.
5 |
6 | The services are APIs are used by TSServer, which creates a `ts.server` SessionClient in `src/harness/client.ts`
7 | (it seems most of the `class`es in the compiler live in the server/services space. Maybe a by-product of working
8 | tightly with the VS Code team? )
9 |
--------------------------------------------------------------------------------
/codebase/src/compiler/types.md:
--------------------------------------------------------------------------------
1 | # Type Hierarchy
2 |
3 | Root class: `Type`
4 |
5 | ### How are properties stored and found on a type?
6 |
7 | `checkPropertyAccessExpressionOrQualifiedName`
8 |
9 | ### getDeclaredTypeOfSymbol vs getTypeOfSymbol
10 |
11 | The problem is that symbols can have both types and values associated with them:
12 |
13 | ```ts
14 | type A = number
15 | const A = "do not do this"
16 | ```
17 |
18 | And the compiler needs a way to get the type of both the type and the const.
19 | So it uses `getDeclaredTypeOfSymbol` for types and `getTypeOfSymbol[AtLocation]` for values:
20 |
21 | ```ts
22 | getDeclaredTypeOfSymbol(A) == number
23 | getTypeOfSymbol(A) == string
24 | ```
25 |
26 | Confusingly, classes (and enums and aliases) declare both a type and a value, so, a tiny bit arbitrarily, the instance side is the type and the static side is the value:
27 |
28 | ```ts
29 | class C {
30 | m() { }
31 | static s() { }
32 | }
33 | getTypeOfSymbol() == { new(): C, s(): void } == typeof C
34 | getDeclaredTypeOfSymbol() == { m(): void } == C
35 | ```
36 |
37 | This kind of makes sense when you think about that C actually does when executed: it defines a value that is constructable.
38 | This leads to the "deconstructed class" pattern used in tricky situations, for example:
39 |
40 | ``` ts
41 | interface C {
42 | m(): void
43 | }
44 | var C: {
45 | new(): C
46 | s: void
47 | }
48 | ```
49 |
50 | Again, it's a tiny bit arbitrary to choose the static side as the value, since ultimately you get a value from calling new C() too.
51 | But the deconstructed class pattern shows that you can get away with writing just a type for the instance side, whereas you must write a value for the static side.
52 |
53 |
54 |
55 | [1]:
58 |
--------------------------------------------------------------------------------
/codebase/src/compiler/utils.md:
--------------------------------------------------------------------------------
1 | ### Util Functions
2 |
3 | Some essentials:
4 |
5 | - [`findAncestor`][0]
6 |
7 | > Iterates through the parent chain of a node and performs the callback on each parent until the callback returns
8 | > a truthy value, then returns that value.
9 | >
10 | > If no such value is found, it applies the callback until the parent pointer is undefined or the callback returns
11 | > "quit" At that point findAncestor returns undefined.
12 |
13 | Basically looks up the AST until it finds something which passes.
14 |
--------------------------------------------------------------------------------
/codebase/src/services/completions.md:
--------------------------------------------------------------------------------
1 | # Completions
2 |
3 |
4 | Completions for TypeScript and JavaScript are provided by TypeScript's language service.
5 | When you are in the middle of typing something in an editor (or if you hit Ctrl + Space in VSCode), the editor sends a request to the TypeScript language service.
6 | Completions is responsible for answering that request with suggestions to *complete* what you are typing.
7 |
8 |
9 | ## Overview
10 |
11 | Most of the implementation lives in the `src/services/completions.ts` file, and there are several steps the implementation goes through to answer a completion request.
12 |
13 | The entry point into completions is `getCompletionsAtPosition()`.
14 | As the name suggests, this function takes a `SourceFile` and a `position` as arguments (among other things), and it returns a [`CompletionInfo`](https://github.com/microsoft/TypeScript/blob/404a7d602df9c19d98d49e6a6bf2295e423be676/src/services/types.ts?#L1172-L1191) object with completions for that specific position.
15 |
16 | `CompletionInfo` has a few different properties, but we're mainly interested in the `entries: CompletionEntry[]` property, because a [`CompletionEntry`](https://github.com/microsoft/TypeScript/blob/404a7d602df9c19d98d49e6a6bf2295e423be676/src/services/types.ts?#L1220-L1249) encodes the suggestions returned.
17 |
18 |
19 | ### Completion entry
20 |
21 | Some `CompletionEntry` properties and what they mean:
22 |
23 | * **name**: the name of that completion entry. Usually if the completion is for an identifier/keyword named `foo`, then the name of the entry is also going to be `foo`.
24 | * **insertText**: the text that is going to be inserted in the file, at the completion position, when the user accepts the suggestion corresponding to this completion entry.
25 | `insertText` is optional, and if it is not present, then `name` is the text that is inserted instead.
26 | * **isSnippet**: if this is true, then this completion entry is a snippet, and `insertText` is a snippet text.
27 | e.g.:
28 | A completion snippet for declaring a method `foo`, with a tab stop (`${0}`) in its body:
29 | ```ts
30 | {
31 | isSnippet: true,
32 | insertText: "foo() { ${0} }",
33 | }
34 | ```
35 | becomes this in VSCode, when accepted (note the cursor position):
36 | 
37 | For more on snippets, see [Snippets in Visual Studio Code](https://code.visualstudio.com/docs/editor/userdefinedsnippets).
38 | * **replacementSpan**: the span (i.e. a continuous range) of the source file that is going to be *replaced* by the text inserted by this completion. It is optional, so we only need to provide this if we want to override the *default* replacement span for this completion entry.
39 | * **hasAction**: whether that completion requires additional actions if it is accepted. For instance, a completion might insert variables that need to be imported, so if that completion is accepted, it needs an additional action of inserting import statements.
40 |
41 | ## Implementation
42 |
43 | `getCompletionsAtPosition()` goes through a lot of steps and additional function calls before returning a `CompletionInfo` response.
44 | Roughly the steps are:
45 | 1. call `getCompletionData` to gather the data needed to construct a `CompletionInfo`.
46 | `getCompletionData`'s returns data including a **list of symbols** for things (e.g. variables, properties) we may want to offer for completions.
47 | 2. We call the appropriate function for transforming the completion data into completion info.
48 | The exact function called depends on the the kind of data returned by `getCompletionData`, which can be:
49 | * `JSDoc`: JSDoc-specific completion data,
50 | * `Keywords`: keyword completion data,
51 | * `Data`: general data not falling into the above categories (aka everything else).
52 |
53 | If the data is of jsdoc kind, then we call `jsdocCompletionInfo`, if it is keyword data we call `specificKeywordCompletionInfo`.
54 | Most importantly, though, when we have the general kind of data, we proceed with **calling `completionInfoFromData`**.
55 | This is the flow you want to look at most of the time, so let's assume we are following this general flow.
56 | 3. `completionInfoFromData` is called with the data we got from `getCompletionData`.
57 | Mainly, it calls `getCompletionEntriesFromSymbols` to construct completion entries from the symbols obtained in `getCompletionData`.
58 |
59 | ### `getCompletionData`
60 |
61 | Step one is to grab [a `CompletionData`][1] via [`getCompletionData`][2]. This function tries to find a context
62 | token which first looks forwards, and then try find a `contextToken`. This is generally the preceding token to
63 | your cursor, as that tends to be the most important thing when deciding what to show next. This takes into account
64 | things like `x.y` and `y?.y` by diving deeper into preceding identifier.
65 |
66 | This dive to find a "responsible" item for a completion request called `node` in the code.
67 |
68 | Next it goes through the following checks for a set of completions.
69 | TODO: continue this.
70 |
71 | ### [`getCompletionEntriesFromSymbols`]((https://github.com/Microsoft/TypeScript/blob/340f81035ff1d753e6a1f0fedc2323d169c86cc6/src/services/completions.ts#L305))
72 |
73 | Some completion scenarios require doing special work when transforming a symbol into a completion entry.
74 | That special work is done here, in `getCompletionEntriesFromSymbols`, when we call `createCompletionEntry`.
75 |
76 | As an example, let's walk through [class member snippet completions](https://github.com/microsoft/TypeScript/pull/46370), a completion scenario that suggests whole class member declarations (i.e. method and property declarations).
77 | In `createCompletionEntry`, we get the symbol for a class member, say a method `foo`, that we want to offer as a completion. First, we detect that this symbol is for a class member (i.e. method `foo`'s symbol).
78 | Then, to turn that symbol into a completion entry, we have to figure out what the `insertText` for the entry must be.
79 | For method `foo`'s completion entry, we decide the `insertText` is going to be the declaration for method `foo`, something like:
80 | ```ts
81 | foo(x: string): number {
82 | // empty implementation
83 | }
84 | ```
85 | So, to get that custom `insertText`, `createCompletionEntry` calls [`getEntryForMemberCompletion`](https://github.com/microsoft/TypeScript/blob/404a7d602df9c19d98d49e6a6bf2295e423be676/src/services/completions.ts#L857).
86 |
87 | Another scenario that works similarly is import completions: in `createCompletionEntry`, we call [`getInsertTextAndReplacementSpanForImportCompletion`](https://github.com/microsoft/TypeScript/blob/404a7d602df9c19d98d49e6a6bf2295e423be676/src/services/completions.ts#L1118) to get the custom `insertText` for a completion for importing a symbol, for instance `import { foo } from "foo"`.
88 |
89 | ## String Literal Completions
90 |
91 | E.g. are you inside a string and asking for completions? TS differentiates between reference comments
92 | ([triple slash](https://www.typescriptlang.org/docs/handbook/triple-slash-directives.html)):
93 |
94 | 
95 |
96 | And strings as a part of the AST. These have a
97 | [few](https://github.com/Microsoft/TypeScript/blob/340f81035ff1d753e6a1f0fedc2323d169c86cc6/src/services/stringCompletions.ts#L103)
98 | different uses:
99 |
100 | - They could be path references
101 | - They could be module references
102 | - They could be indexed keys from an object
103 | - They could be parts of a union object
104 |
105 | ####
106 |
107 |
108 | [1]: https://github.com/microsoft/TypeScript/blob/db9e0079/src/services/completions.ts#L1525
109 | [1]:
110 | [2]: https://github.com/microsoft/TypeScript/blob/db9e0079/src/services/completions.ts#L1618
111 | [2]:
112 |
113 |
--------------------------------------------------------------------------------
/codebase/src/services/textChanges.md:
--------------------------------------------------------------------------------
1 | # Text Changes
2 |
3 | The majority of this file is devoted to a class called the [`ChangeTracker`][0]. This class is nearly always
4 | created via `ChangeTracker.with` where you would give it a context object.
5 |
6 | Here is an example context object:
7 |
8 | ```ts
9 | {
10 | cancellationToken:CancellationTokenObject {cancellationToken: TestCancellationToken}
11 | errorCode:2304
12 | formatContext:Object {options: Object, getRule: }
13 | host:NativeLanguageServiceHost {cancellationToken: TestCancellationToken, settings: Object, sys: System, …}
14 | preferences:Object {}
15 | program:Object {getRootFileNames: , getSourceFile: , getSourceFileByPath: , …}
16 | sourceFile:SourceFileObject {pos: 0, end: 7, flags: 65536, …}
17 | span:Object {start: 0, length: 6}
18 | }
19 | ```
20 |
21 | You only really see `ChangeTrack` in use within the codefixes and refactors given that the other case where
22 | TypeScript emits files is a single operation of emission.
23 |
24 | The change tracker keeps track of individual changes to be applied to a file. There are [currently][1] four main
25 | APIs that it works with:
26 | `type Change = ReplaceWithSingleNode | ReplaceWithMultipleNodes | RemoveNode | ChangeText;`
27 |
28 | The `ChangeTrack` class is then used to provide high level API to describe the sort of changes you might want to
29 | make, which eventually fall into one of the four categories above.
30 |
31 | ### Making Changes
32 |
33 | The end result of using a `ChangeTrack` object is an array of `FileTextChanges` objects. The `ChangeTrack.with`
34 | function lets you work with a tracker instance elsewhere and passes back the `ChangeTrack` objects.
35 |
36 | The core work in generating changes occurs in:
37 |
38 | - [`getTextChangesFromChanges`][4]
39 | - [`computeNewText`][5]
40 | - [`getFormattedTextOfNode`][6]
41 |
42 | Going from an AST node to text is done by creating a [`printer`][7] in [`getNonformattedText`][8]. The printer
43 | returns an unformatted node, which is then ran through [a formatter][./formatting.md] and the raw string
44 | substitution is done in [`applyChanges`][9].
45 |
46 | Changes look like this:
47 |
48 | ```ts
49 | [{ fileName: "/b.js", textChanges: [{ span: { start: 0, length: 0 }, newText: "// @ts-ignore\n" }] }];
50 | ```
51 |
52 | ### Writing
53 |
54 | [`newFileChanges`][3] handles passing the set of
55 |
56 |
57 | [0]: https://github.com/microsoft/TypeScript/blob/db9e0079/src/services/textChanges.ts#L303
58 | [0]:
59 | [1]: https://github.com/microsoft/TypeScript/blob/db9e0079/src/services/textChanges.ts#L136
60 | [1]:
61 | [2]: https://github.com/microsoft/TypeScript/blob/db9e0079/src/services/textChanges.ts#L1134
62 | [2]:
63 | [3]: https://github.com/microsoft/TypeScript/blob/db9e0079/src/services/textChanges.ts#L1022
64 | [3]:
65 | [4]: https://github.com/microsoft/TypeScript/blob/db9e0079/src/services/textChanges.ts#L994
66 | [4]:
67 | [5]: https://github.com/microsoft/TypeScript/blob/db9e0079/src/services/textChanges.ts#L1035
68 | [5]:
69 | [6]: https://github.com/microsoft/TypeScript/blob/db9e0079/src/services/textChanges.ts#L1065
70 | [6]:
71 | [7]: https://github.com/microsoft/TypeScript/blob/db9e0079/src/compiler/emitter.ts#L852
72 | [7]:
73 | [8]: https://github.com/microsoft/TypeScript/blob/db9e0079/src/services/textChanges.ts#L1088
74 | [8]:
75 | [8]: https://github.com/microsoft/TypeScript/blob/db9e0079/src/services/textChanges.ts#L1101
76 | [8]:
77 |
78 |
--------------------------------------------------------------------------------
/intro/README.md:
--------------------------------------------------------------------------------
1 | ## The TypeScript Compiler
2 |
3 | There's a lot to learn, and this document is going to try and give you a very high level overview of how the
4 | TypeScript compiler works and how you can contribute to it.
5 |
6 | Here are the key sections in this docs:
7 |
8 | - [Getting Set up](#getting-set-up)
9 | - [What is in the TypeScript repo?](#what-is-in-the-typescript-repo)
10 | - [The TypeScript Compiler](#the-typescript-compiler)
11 | - [The TSServer](#the-tsserver)
12 | - [Tips and Tricks](#tips-and-tricks)
13 |
14 | ## Getting Set Up
15 |
16 | You need a modern version [of Node.js](https://nodejs.org/en/) installed and then:
17 |
18 | - Clone the repo: `git clone https://github.com/microsoft/TypeScript`
19 | - `cd TypeScript`
20 | - `npm i` - installs dependencies
21 | - `npm run gulp` - builds the TypeScript compiler
22 | - `code .` then briefly come back to terminal to run:
23 | - `npm test`
24 |
25 | With that done, you should have a copy of the compiler up and running with tests running in the background to
26 | prove that everything is working correctly. This could take around 10m, you should see be a progress indicator in
27 | your terminal.
28 |
29 | ### What happened during setup
30 |
31 | TypeScript is built in TypeScript. The compiler uses a "last known good" version of the TypeScript to bootstrap,
32 | you can find this version in `/lib`. The command `npm run gulp` created a copy of the compiler at `built/local`.
33 | The corresponding version of the `tsc` compiler used in the npm package is now available via:
34 | `node built/local/tsc.js --help`.
35 |
36 | TypeScript has a _comprehensive_ test suite, most of the tests are high level integration tests which you can find
37 | at `tests/cases`. Given the scope and depth of a compiler like TypeScript, we use a lot of tests to ensure
38 | improvements don't break old requirements.
39 |
40 | ### Configuring your editor
41 |
42 | To get your VS Code environment working smoothly, set up the per-user config:
43 |
44 | - Set up your `.vscode/launch.json` by running: `cp .vscode/launch.template.json .vscode/launch.json`
45 | - Set up your `.vscode/settings.json` by running: `cp .vscode/settings.template.json .vscode/settings.json`
46 |
47 | ## What is in the TypeScript repo?
48 |
49 | The TypeScript repo is a single codebase which creates a set of files which are released as the "typescript" npm
50 | module:
51 |
52 | - `typescript.js` - The compiler API
53 | - `tsc.js` - The command line experience for using TypeScript, which uses `typescript.js`
54 | - `typescriptServices.js` - A web server which responds to questions about TS/JS code from editors, which uses
55 | `typescript.js`
56 | - `tsserver.js` - The command line wrapper for `typescriptServices.js`
57 |
58 | You can consider there to be three main entry points into TypeScript: Directly via
59 | `import * as ts from "typescript"`, the CLI and tsserver.
60 |
61 | 
62 |
63 | We'll be concentrating on an overview of these two parts: The TypeScript compiler and tsserver
64 |
65 | ### The TypeScript Compiler
66 |
67 | The goal of the TypeScript compiler is to take a collection of `*.ts`/`*.js`/`*.json`/`*.d.ts` source files,
68 | _optionally_ run a type checker over those files, and emit corresponding `*.js`/`*.d.ts`/`*.js.map` files.
69 |
70 | Abstractly, you can think of the compiler as going through this linear process (in reality it gets a little more
71 | complicated, but as an overview it's fine) to achieve its goal:
72 |
73 | 
74 |
75 | Let's go through these systems at a high level, indicating what sort of bugs or features might touch them.
76 |
77 | #### Parsing Text
78 |
79 | The Parser is an object which controls a Scanner. The Scanner iterates (mostly) forwards through the source code's
80 | text, dividing it into a sequence of words and punctuation.
81 |
82 | For example:
83 |
84 | ```ts
85 | function hello() {
86 | console.log("Hi");
87 | }
88 | ```
89 |
90 | Produces a scanner result of:
91 | `FunctionKeyword, WhitespaceTrivia, Identifier, OpenParenToken, CloseParenToken, WhitespaceTrivia, OpenBraceToken, NewLineTrivia, WhitespaceTrivia, Identifier, DotToken, Identifier, OpenParenToken, StringLiteral, CloseParenToken, SemicolonToken, NewLineTrivia, CloseBraceToken, EndOfFileToken`.
92 | You can use [this playground plugin](https://www.typescriptlang.org/play?install-plugin=playground-ts-scanner) to
93 | see the tokens from a scanner for any TS/JS code.
94 |
95 | The parser will take that set of syntax tokens and form a syntax tree which is a series of nested nodes starting
96 | at a `SourceFile`:
97 |
98 | ```
99 | SourceFile:
100 | - statements: [
101 | Function Declaration
102 | - name: Identifier
103 | - body: Block
104 | statements: [
105 | ExpressionStatement
106 | expression: CallExpress
107 | ...
108 | ]
109 | ]
110 | ```
111 |
112 | This is the TypeScript syntax tree, and it is one of the core data models in the compiler as it represents the
113 | structure of the code in memory. You can explore the TypeScript syntax tree in
114 | [the Playground](https://www.typescriptlang.org/play/#code/GYVwdgxgLglg9mABACwKYBt1wBQEpEDeAUIohAgM5zqoB0WA5tgEQASMzuA3EQL5A)
115 | (by turning on the "AST" setting) or in
116 | [TypeScript AST Viewer](https://ts-ast-viewer.com/#code/GYVwdgxgLglg9mABACwKYBt1wBQEpEDeAUIohAgM5zqoB0WA5tgEQASMzuA3EQL5A).
117 |
118 | Common changes to the parser are ones that add TypeScript syntax that does not exist in JavaScript, or adds new JavaScript syntax
119 | that was approved by the TC39 committee.
120 |
121 | #### Type Checking
122 |
123 | TypeScript's type system works by creating symbols when "something" is declared in a scope. That "something" could
124 | be a variable, type, interface, function or more. A symbol has a set of flags that indicate what kind(s) of
125 | declaration(s) it's for. Symbols are then compared to each other during assignment and are used throughout the type system for
126 | checking.
127 |
128 | For example, this code:
129 |
130 | ```ts
131 | function hello() {
132 | console.log("Hi");
133 | }
134 |
135 | hello;
136 | ```
137 |
138 | creates one new symbol `hello` whose declaration is the function `hello`. The following flag is set:
139 | `SymbolFlags.Function`. The compiler looks up this symbol whenever the name `hello` appears, like on the last line of the code.
140 | You can use [this playground plugin](https://www.typescriptlang.org/play?install-plugin=playground-ts-symbols) to see the
141 | symbols generated for any TS/JS code.
142 |
143 | Creating symbols is the responsibility of the binder, which is the first part of the type checking process.
144 |
145 | Type checking in TypeScript happens in the file `checker.ts`, this is a 40k line function which does a huge amount
146 | of work. The checker works primarily by recursively diving into, known as "walking", the syntax tree, and making assertions about the
147 | nodes on its way through.
148 |
149 | As a rough outline, using the code above, the following functions in the checker would be called:
150 |
151 | ```
152 | checkSourceFileWorker (for the root SourceFile)
153 | - checkSourceElementWorker (for each Statement)
154 | - checkFunctionDeclaration (for the Function Declaration)
155 | - checkBlock (for the function's body Block)
156 | ...
157 | ```
158 |
159 | Effectively each syntax node has its own type checking function, and that's usually a good place to start if you
160 | want to add or amend a diagnostic which TypeScript raises.
161 |
162 | Common changes to the type checker are PRs which revise, fix or create new error diagnostics around code patterns.
163 |
164 | #### Emit
165 |
166 | The code in `emitter.ts` creates output `.js`, `.d.ts`, `.map` files from `.js` or `.ts` files.
167 |
168 | The emitter first uses a series of transformers to take the input file's syntax tree and convert that into a new
169 | syntax tree which fits the constraints of the tsconfig. For example if your target was `es2015` then the
170 | transformers for Class Fields, ESNext, ES2020, ES2019, ES2018, ES2017, ES2016, ES2015, and Generators would run.
171 | You can use
172 | [this playground plugin](https://www.typescriptlang.org/play?install-plugin=playground-transformer-timeline) to
173 | see the individual transformations for any TS/JS code.
174 |
175 | After the transforms are finished, the emitter recurses through the new syntax tree printing out nodes into a
176 | new text file.
177 |
178 | Common changes to the emitter are PRs which transform new TypeScript syntax, or new JavaScript features from TC39,
179 | into JavaScript that works on older platforms.
180 |
181 | ## TSServer
182 |
183 | The TSServer is responsible for providing information to text editors. The TSServer powers features like code
184 | completion, refactoring tools and jump to definition. The TSServer is similar to the language server protocol
185 | but is older.
186 |
187 | ## Tips and Tricks
188 |
189 | ### Start with 'backlog', 'good first issues' or 'help wanted' issues
190 |
191 | There are thousands of issues on the TypeScript repo, and we triage them all. The issues which we have already
192 | confirmed mean there is less need to have discussion ahead of time.
193 |
194 | - [Good first issues](https://github.com/microsoft/TypeScript/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22)
195 | - [Help wanted](https://github.com/microsoft/TypeScript/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22)
196 | - [Backlog](https://github.com/microsoft/TypeScript/milestone/29)
197 |
198 | ### Look for similar merged PRs
199 |
200 | If your goal is to fix or amend an existing system, then it's quite likely that similar code has been created,
201 | there have already been 10k merged PRs to TypeScript. Finding a similar PR can really help narrow down where your
202 | existing change lives and how it can be tested.
203 |
204 | ### Starting with a diagnostic message
205 |
206 | If you have an existing error message, and are looking to work around that area. All _english_ messages are stored
207 | in `src/compiler/diagnosticInformationMap.generated.ts`, first find the message you are working from, then search
208 | the codebase for the key in that file. E.g:
209 |
210 | - Search `diagnosticInformationMap.generated.ts` for "Convert invalid character to its html entity code"
211 | - Find the line
212 | `Convert_invalid_character_to_its_html_entity_code: diag(95100, DiagnosticCategory.Message, "Convert_invalid_character_to_its_html_entity_code_95100", "Convert invalid character to its html entity code")`
213 | - Search the codebase for `Convert_invalid_character_to_its_html_entity_code` to find its usage
214 |
215 | ### Embrace the debugger
216 |
217 | You'll probably spend a good amount of time in the debugger, if this is completely new to you. [Here is a video from](https://www.youtube.com/watch?v=ChQ_sYjU8tU)
218 | [@alloy](https://github.com/alloy) covering the usage of the debugger inside VS Code, what the buttons do and how it all works.
219 |
220 | To test it out the debugger, open up `src/compiler/checker.ts` find
221 | `function checkSourceFileWorker(node: SourceFile) {` and add a `debugger` statement on the first line in the
222 | function.
223 |
224 |
225 | ```diff
226 | function checkSourceFileWorker(node: SourceFile) {
227 | + debugger
228 | const links = getNodeLinks(node);
229 | ```
230 |
231 | Breakpoints will work too.
232 |
233 | If you open up `tests/cases/fourslash/getDeclarationDiagnostics.ts` and then run your new debugging launch task
234 | `Mocha Tests (currently opened test)`. VS Code will switch into the debugging mode and hit the debugger statement
235 | in your TypeScript.
236 |
237 | You'll probably want to add the following to your watch section in VS Code:
238 |
239 | - `node.__debugKind`
240 | - `node.__debugGetText()`
241 | - `source.symbol.declarations[0].__debugKind`
242 | - `target.symbol.declarations[0].__debugKind`
243 |
244 | This is really useful for keeping track of changing state, and it's pretty often that those are the names of
245 | things you're looking for.
246 |
247 | ### Testing your changes
248 |
249 | There are three main testing systems in the compiler:
250 |
251 | - **Baselines**: Baseline tests are file-based snapshot tests, each test verifies the compiler's output based on
252 | an input file. You can use comments starting with @ to set compiler flags in that test: `// @target: es5`.
253 | - **Fourslash**: Fourslash tests are unit tests which set up a virtual file system in any comment with four
254 | slashes `////`. Then test has a custom set of functions which interact with that virtual file system like a text
255 | editor would.
256 | - **Unit tests**: These are traditional mocha unit tests
257 |
258 | You run tests via `gulp runtests`.
259 |
260 | Flags worth knowing:
261 |
262 | - `--failed` - re-runs the failed tests only
263 | - `--no-lint` - don't run the linter when it completes
264 | - `-i` - Use the inspector to debug
265 |
266 | If you have a change to the in the baselines:
267 |
268 | - `gulp diff` - to see the differences
269 | - `gulp baseline-accept` to overwrite the current baseline snapshots
270 |
--------------------------------------------------------------------------------
/intro/imgs/compiler-linear.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/TypeScript-Compiler-Notes/31425672133e15f4e61f52a0f541d060f239e915/intro/imgs/compiler-linear.png
--------------------------------------------------------------------------------
/intro/imgs/layers-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/TypeScript-Compiler-Notes/31425672133e15f4e61f52a0f541d060f239e915/intro/imgs/layers-2.png
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "markdown-magic": "^1.0.0",
4 | "typescript": "latest",
5 | "glob": "^7.1.6",
6 | "escape-regex-string": "^1.0.6"
7 | },
8 | "scripts": {
9 | "update": "node scripts/convertRelativeLinksToHardcoded.js **/*.md"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/scripts/updateFindLinks.js:
--------------------------------------------------------------------------------
1 | // @ts-check
2 |
3 | // Loop through all files switching a reference like:
4 | //
5 | // [13]:
6 | //
7 | // to
8 | //
9 | // [13]: https://github.com/microsoft/TypeScript/blob/8d986554/src/compiler/checker.ts#L30308
10 | // [13]:
11 | //
12 | // GitHub uses the first link and ignores the 2nd. If the dupe is already there,
13 | // then it updates to a new url.
14 |
15 | // Validate:
16 | // node scripts/updateFindLinks.js scripts/fixtures/input.md
17 |
18 | // Write:
19 | // node scripts/updateFindLinks.js scripts/fixtures/input.md --write
20 |
21 | const glob = require("glob");
22 | const { readFileSync, writeFileSync, existsSync } = require("fs");
23 | const { join } = require("path");
24 | const { execSync } = require("child_process");
25 | const escapeRegex = require("escape-regex-string");
26 |
27 | if (!process.argv[2]) throw new Error("Did not include a glob for markdown files to change");
28 |
29 | // This can be anything
30 | const write = process.argv[3] !== undefined;
31 |
32 | const possibleTSRepo = ["../typescript-compiler", "../TypeScript", "TypeScript"];
33 | let repoPath = possibleTSRepo.find(f => existsSync(join(f, "package.json")));
34 | if (!repoPath) throw new Error("Could not find a TypeScript repo");
35 |
36 | const repoHead = execSync(`git rev-parse HEAD | cut -c 1-8`, { cwd: repoPath, encoding: "utf8" });
37 | if (!repoHead) throw new Error("Could not get the git info from the sibling TypeScript repo");
38 |
39 | const files = glob.sync(process.argv[2]);
40 | if (!files.length) throw new Error("Did not get any files with that glob");
41 |
42 | let failed = [];
43 |
44 | files.forEach(file => {
45 | if (file === "README.md") return;
46 |
47 | let content = readFileSync(file, "utf8");
48 | // https://regex101.com/r/w1dEG1/1
49 | const regex = new RegExp(/\[.*]: <(.*) - (.*)>/g);
50 |
51 | const matches = content.matchAll(regex)
52 | for (const result of matches) {
53 | const fileRef = result[1];
54 | const searchTerm = result[2];
55 | const original = `: <${fileRef} - ${searchTerm}>`;
56 | const originalLine = getLineOfStr(content, original)[0].number
57 | const reference = lineOfStr(content, originalLine-1).slice(1).split("]")[0]
58 | const lineToChange = lineOfStr(content, originalLine-2)
59 | const shouldReplace = lineToChange.includes("/blob/")
60 | try {
61 | const originalFile = readFileSync(join(repoPath, fileRef), "utf8");
62 | const line = getLineNo(originalFile, new RegExp(escapeRegex(searchTerm)));
63 | const lineRef = line && line[0] && line[0].number ? `#L${line[0].number}` : "";
64 | const replacement = `[${reference}]: https://github.com/microsoft/TypeScript/blob/${repoHead.trim()}/${fileRef}${lineRef}`;
65 | content = content.replace(lineToChange, shouldReplace ? replacement : lineToChange + "\n" + replacement);
66 | } catch (e) {
67 | console.log(e)
68 | failed.push([file, fileRef]);
69 | }
70 | }
71 |
72 | if (write) {
73 | writeFileSync(file, content);
74 | } else {
75 | console.log(content);
76 | }
77 | });
78 |
79 | if (failed.length) {
80 | console.error("Could not find the following references to update:");
81 | console.error(failed);
82 |
83 | console.error("Either ping @orta if confused about this failure, or update the filepaths please. It's likely they've moved in the TypeScript repo.");
84 | process.exit(1);
85 | }
86 |
87 | function lineOfStr(str, idx) {
88 | return str.split(/\r?\n/)[idx]
89 | }
90 |
91 | function getLineOfStr(str, substr) {
92 | return str
93 | .split(/\r?\n/)
94 | .map(function(line, i) {
95 | if (line.includes(substr)) {
96 | return {
97 | number: i + 1,
98 | line
99 | };
100 | }
101 | })
102 | .filter(Boolean);
103 | }
104 |
105 |
106 | /*!
107 | * line-number
108 | *
109 | * Copyright (c) 2014 Jon Schlinkert, contributors.
110 | * Licensed under the MIT License
111 | */
112 | function getLineNo(str, re) {
113 | return str
114 | .split(/\r?\n/)
115 | .map(function(line, i) {
116 | if (re.test(line)) {
117 | return {
118 | line: line,
119 | number: i + 1,
120 | match: line.match(re)[0]
121 | };
122 | }
123 | })
124 | .filter(Boolean);
125 | }
126 |
--------------------------------------------------------------------------------
/systems/cli.md:
--------------------------------------------------------------------------------
1 | ## CLI
2 |
3 | Oddly, the TS Config is probably best described by the CLI which you can find in
4 | `src/compiler/commandLineParser.ts`.
5 |
6 | The CLI starts after parsing [`tsc.ts`][0] which triggers [`executeCommandLine`][1]. This function handles going
7 | from an arg list to structured data in the form of [ParsedCommandLine][2].
8 |
9 | The actual work occurs in [`parseCommandLineWorker`][] which sets up some variables:
10 |
11 | ```ts
12 | const options = {} as OptionsBase;
13 | const fileNames: string[] = [];
14 | const errors: Diagnostic[] = [];
15 | ```
16 |
17 | Then it starts If the letter is a - then start looking forwards to see if the arg is available in [the
18 | optionmap][4]
19 |
20 | function executeCommandLine
21 |
22 | [0]: src/tsc/tsc.ts
23 | [1]:
24 | [2]:
25 | [3]:
26 | [4]:
27 |
--------------------------------------------------------------------------------
/systems/codefixes.md:
--------------------------------------------------------------------------------
1 | ### How do Codefixes work
2 |
3 | A codefix is a signal from TypeScript to an editor that it's possible for TypeScript to provide an automated fix
4 | for some particular part of a codebase.
5 |
6 | Codefixes are implemented in a way that always requires there to be an error code, which means they bubble through
7 | TypeScript's internals initially from a compiler error.
8 |
9 | ### Codefix vs Refactor
10 |
11 | Code fixes have an associated error code, and can be skipped cheaply when trying to figure out if it's applicable.
12 | A refactor on the other hand does not come from an error code and is therefore somewhat always available, and are
13 | more expensive to check for.
14 |
15 | ### How are they used?
16 |
17 | The code fix assertions come in from comes in from the language service, via [`getCodeFixesAtPosition`][1], this
18 | says here's a file and a selection range for their selected text and any potential compiler error codes that touch
19 | section.
20 |
21 | The language service then reaches into [the codeFixProvider][2] via [`getFixes`][3], this delegates its work to
22 | [`getCodeActions`][4] which is a function which each codefix provides.
23 |
24 | These are returned to the IDE in the form of an object with:
25 |
26 | ```ts
27 | interface CodeAction {
28 | /** Description of the code action to display in the UI of the editor */
29 | description: string;
30 | /** Text changes to apply to each file as part of the code action */
31 | changes: FileTextChanges[];
32 | /**
33 | * If the user accepts the code fix, the editor should send the action back in a `applyAction` request.
34 | * This allows the language service to have side effects (e.g. installing dependencies) upon a code fix.
35 | */
36 | commands?: CodeActionCommand[];
37 |
38 | /** Short name to identify the fix, for use by telemetry. */
39 | fixName: string;
40 | /**
41 | * If present, one may call 'getCombinedCodeFix' with this fixId.
42 | * This may be omitted to indicate that the code fix can't be applied in a group.
43 | */
44 | fixId?: {};
45 | fixAllDescription?: string;
46 | }
47 | ```
48 |
49 | An example of one is:
50 |
51 | ```ts
52 | const codefix = {
53 | description: `Import 'moment' from module "moment"`,
54 | fixAllDescription: "Add all missing imports",
55 | fixId: "fixMissingImport",
56 | fixName: "import"
57 | };
58 | ```
59 |
60 | ### Testing a code fix
61 |
62 | You can use fourslash to set up a project that emulates the sort of before and after experience from your codefix
63 |
64 | ```ts
65 | ///
66 | // #29038
67 |
68 | // @allowJs: true
69 | // @checkJs: true
70 | // @esModuleInterop: true
71 | // @moduleResolution: node
72 |
73 | // @Filename: /node_modules/moment.d.ts
74 | ////declare function moment(): void;
75 | ////export = moment;
76 |
77 | // @Filename: /b.js
78 | ////[|moment;|]
79 |
80 | goTo.file("/b.js");
81 | verify.importFixAtPosition([
82 | `import moment from "moment";
83 |
84 | moment;`
85 | ]);
86 | ```
87 |
88 | ### Example codefix PRs
89 |
90 | These are some reference PRs to look at
91 |
92 | - https://github.com/microsoft/TypeScript/pull/23711
93 | - https://github.com/microsoft/TypeScript/pull/32281
94 |
95 |
96 | [1]:
97 | [2]: src/services/codeFixProvider.ts
98 | [3]:
99 | [4]:
100 |
101 |
--------------------------------------------------------------------------------
/systems/debugging/printing.md:
--------------------------------------------------------------------------------
1 | ## For `console.log` debugging
2 |
3 | A lot of the time to see what the code you're representing you want to look in either `declaration` or
4 | `declarations`. These are Node subclasses which means they'll have a copy of `__debugGetText()` which should get
5 | you to the syntax representation.
6 |
7 | ### An XXYYFlags
8 |
9 | [Run](https://twitter.com/atcb/status/1174747774761324544) `ts.Debug.format[Whatever]Flags(flag)` in the console
10 | to find out the constituent parts
11 |
12 | ### `Type`
13 |
14 | Useful: `console.log(type.__debugKind)`.
15 |
16 | Chances are through you want to go through symbol though
17 |
18 | ### `Symbol`
19 |
20 | Using `symbolToString(symbol)` could get you somewhere, but so far that's not been
21 |
22 | ### `Node`
23 |
24 | ### `Signature`
25 |
26 | `signature.declaration.__debugGetText()`
27 |
--------------------------------------------------------------------------------
/systems/debugging/settings.md:
--------------------------------------------------------------------------------
1 | Here are some launch.json configurations that sandersn uses
2 |
3 | ## Hard-coded file:
4 |
5 | This starts much faster than a full test run. I update the compiler flags each time I debug something new.
6 |
7 | {
8 | "name": "welove.ts",
9 | "program": "${workspaceRoot}/built/local/tsc.js",
10 | "request": "launch",
11 | "skipFiles": [
12 | "/**"
13 | ],
14 | "sourceMaps": true,
15 | "smartStep": true,
16 | "args": ["--noEmit", "--skipLibCheck", "--strict", "--exactOptionalPropertyTypes", "/home/nathansa/src/test/welove.ts"],
17 | "env": {
18 | "NODE_ENV": "testing"
19 | },
20 | "type": "pwa-node",
21 | "console": "integratedTerminal",
22 | "outFiles": [ "${workspaceRoot}/built/local/tsc.js"]
23 | },
24 |
25 | I also have a Javascript and JSX target that are nearly identical.
26 |
27 | ## Currently opened test
28 |
29 | This debugs the current test file that's open in VS Code.
30 |
31 | {
32 | "type": "pwa-node",
33 | "protocol": "inspector",
34 | "request": "launch",
35 | "name": "Mocha Tests (currently opened test)",
36 | "runtimeArgs": ["--nolazy"],
37 | "program": "${workspaceRoot}/node_modules/mocha/bin/_mocha",
38 | "args": [
39 | "-u",
40 | "bdd",
41 | "--no-timeouts",
42 | "--colors",
43 | "built/local/run.js",
44 | "-f",
45 | // You can change this to be the name of a specific test file (without the file extension)
46 | // to consistently launch the same test
47 | "${fileBasenameNoExtension}",
48 | ],
49 | "env": {
50 | "NODE_ENV": "testing"
51 | },
52 | "sourceMaps": true,
53 | "smartStep": true,
54 | "preLaunchTask": "gulp: tests",
55 | "console": "integratedTerminal",
56 | "outFiles": [
57 | "${workspaceRoot}/built/local/run.js"
58 | ]
59 | },
60 |
61 | I also made a hard-coded variant, as suggested by the comment.
62 |
63 | ## Attach to running tsc
64 |
65 | This is sometimes useful when I want to build a complex project with `tsc -b` and then debug it.
66 |
67 | {
68 | "name": "9229",
69 | "port": 9229,
70 | "request": "attach",
71 | "skipFiles": [
72 | "/**"
73 | ],
74 | "type": "pwa-node",
75 | "env": {
76 | "NODE_ENV": "testing"
77 | },
78 | "sourceMaps": true,
79 | "outFiles": [ "${workspaceRoot}/built/local/tsc.js"]
80 | },
81 |
--------------------------------------------------------------------------------
/systems/formatting/formatting.md:
--------------------------------------------------------------------------------
1 | # How does TypeScript formatting work?
2 |
3 | To format code you need to have a formatting context and a `SourceFile`. The formatting context contains all user
4 | settings like tab size, newline character, etc.
5 |
6 | The end result of formatting is represented by TextChange objects which hold the new string content, and the text
7 | to replace it with.
8 |
9 | ```ts
10 | export interface TextChange {
11 | span: TextSpan; // start, length
12 | newText: string;
13 | }
14 | ```
15 |
16 | ## Internals
17 |
18 | Most of the exposed APIs internally are `format*` and they all set up and configure `formatSpan` which could be
19 | considered the root call for formatting. Span in this case refers to the range of the sourcefile which should be
20 | formatted.
21 |
22 | The formatSpan then uses a scanner (either with or without JSX support) which starts at the highest node the
23 | covers the span of text and recurses down through the node's children.
24 |
25 | As it recurses, `processNode` is called on the children setting the indentation is decided and passed through into
26 | each of that node's children.
27 |
28 | The meat of formatting decisions is made via `processPair`, the pair here being the current node and the previous
29 | node. `processPair` which mutates the formatting context to represent the current place in the scanner and
30 | requests a set of rules which can be applied to the items via `createRulesMap`.
31 |
32 | There are a lot of rules, which you can find in [rules.ts](./rules.ts) each one has a left and right reference to
33 | nodes or token ranges and note of what action should be applied by the formatter.
34 |
35 | ## Rules
36 |
37 | ### Where is this used?
38 |
39 | The formatter is used mainly from any language service operation that inserts or modifies code. The formatter is
40 | not exported publicly, and so all usage can only come through the language server.
41 |
--------------------------------------------------------------------------------
/systems/refactor.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/TypeScript-Compiler-Notes/31425672133e15f4e61f52a0f541d060f239e915/systems/refactor.md
--------------------------------------------------------------------------------
/systems/sourcemaps.md:
--------------------------------------------------------------------------------
1 | ### Nodes
2 |
3 | Every node in the TS AST has an optional `emitNode`, this node provides a sort of wrapping context to a node when
4 | it is emitted. For example it keeps track of trailing/leading comments and importantly for sourcemaps:
5 | `sourceMapRange` and `tokenSourceMapRange`.
6 |
7 | These are applied via code transformers in TypeScript
8 |
9 | ### Creating the Files
10 |
11 | Files are created inside `emitter.ts` - the opening function being `emitWorker`.
12 |
13 | - Each source file then gets `writeFile` called on it which triggers the AST traversal on the source file
14 | - A `sourceMapGenerator` is created
15 | - Each node gets triggered via `pipelineEmit`
16 | - `pipelineEmit` runs all transformers against the node
17 | - This is where the pipeline-ing for TS -> ES2020 -> ES2018 -> ES2017 -> ES2015 -> ES6 happens to that node
18 | - Each node calls `emitSourcePos` which tells the `sourceMapGenerator` that a mapping exists for this node
19 |
20 | This means when looking into how TS handles sourcemap, you need to find the part of the above pipeline which
21 | transforms the syntax you're looking for.
22 |
--------------------------------------------------------------------------------
/systems/testing/README.md:
--------------------------------------------------------------------------------
1 | ### Tests for TypeScript
2 |
3 | Yep, TypeScript has tests. Quite a lot, with a few different techniques:
4 |
5 | - [Unit Tests](./units.md)
6 | - [Baselines](./baselines.md)
7 | - [Fourslash](./fourslash.md)
8 |
9 | ## Commands worth knowing
10 |
11 | You run tests via `gulp runtests`.
12 |
13 | Flags worth knowing:
14 |
15 | - `--failed` - re-runs the failed tests only
16 | - `--no-lint` - don't run the linter when it completes
17 | - `-i` - Use the inspector to debug
18 |
19 | If you have a fail in the baselines:
20 |
21 | - `gulp diff` - to see the differences
22 | - `gulp baseline-accept` to overwrite the current baseline snapshots
23 |
--------------------------------------------------------------------------------
/systems/testing/baselines.md:
--------------------------------------------------------------------------------
1 | # Baselines
2 |
3 | Baseline tests are effectively large folder-based snapshot tests. Like [fourslash](./fourslash), these tests are
4 | somewhat integration level. These test generally test the internals of the compiler, they do this by you creating
5 | a TypeScript file where the snapshot result is a symbol map of all the symbols in that file and a list of all
6 | raised errors then compiling the tests.
7 |
8 | ### How to make a baseline
9 |
10 | 1. Make a new file: ` touch tests/cases/compiler/overloadFunctionsNotEqualToGenerics.ts`. Add some TypeScript to
11 | it.
12 | 2. d
13 |
14 | ### How to amend a baseline
15 |
16 | `gulp runtests` will run all the baselines eventually. Or `gulp runtests -i --tests=baseline` should speed things
17 | up if you only want to see those specific changes.
18 |
19 | All of the baselines exist in `tests/baselines/local/`. They kinda look like:
20 |
21 | ```sh
22 | $ tree tests/baselines/local/
23 | tests/baselines/local/
24 | └── api
25 | ├── tsserverlibrary.d.ts
26 | └── typescript.d.ts
27 |
28 | 1 directory, 2 files
29 | ```
30 |
31 | This lets you know that two tests have changed from what you expect. They live in `local/api`, so you can compare
32 | the folders. I normally use [Kaleidoscope](https://www.kaleidoscopeapp.com), but the team loves
33 | [Beyond Compare](https://scootersoftware.com) - it's a bit Windows-y but does a good job showing you how the
34 | folder infrastructure differs.
35 |
36 | 
37 |
38 | Once you're happy with the new baselines, you can run `gulp baseline-accept` to move them into the codebase. You
39 | will be able to see your diffs in git now. :+1:
40 |
--------------------------------------------------------------------------------
/systems/testing/fourslash.md:
--------------------------------------------------------------------------------
1 | # Fourslash
2 |
3 | The fourslash tests are an integration level testing suite. By this point they have a very large API surface, and
4 | tend to cover a lot of the "user-facing" aspects of TypeScript. E.g. things which an IDE might have an interest in
5 | knowing.
6 |
7 | ### How to run one
8 |
9 | `gulp runtests` will run all the fourslash tests eventually. Or `gulp runtests -i --tests=[filename]` should speed
10 | things up if you only want to see those specific changes.
11 |
12 | ### How Fourslash runs a test
13 |
14 | Fourslash automatically generates mocha tests based on files you put inside [`/tests/cases/fourslash`][0] the code
15 | for this lives in [`/src/testRunner/fourslashRunner.ts`][1]. This class is instantiated in
16 | [`/src/testRunner/runner.ts`][2].
17 |
18 | From here the main work all lives in [`/src/harness/foudslash.ts`][3] where we'll be spending the rest of this
19 | section. The initial entry point is [`runFourSlashTest`][4] but the work is in [`runFourSlashTestContent`][5].
20 |
21 | This function first creates a virtual fs, uses [`parseTestData`][6] to fill up the virtual fs. `parseTestData`:
22 |
23 | - Loops through every line in the test file
24 | - If the line starts with `////` then it starts piping the text into a new string which represents the current
25 | file
26 | - If the line starts with `//` then check whether it's a special case variable (like `Filename`) - if it's not
27 | then it will get passed as though it were a TSConfig setting.
28 |
29 | This isn't `eval`-ing the code, so the tests under are ignored. Here's an example test file:
30 |
31 | ```ts
32 | ///
33 | // #29038
34 |
35 | // @allowJs: true
36 | // @checkJs: true
37 |
38 | // @Filename: /node_modules/moment.d.ts
39 | ////declare function moment(): void;
40 | ////export = moment;
41 |
42 | // @Filename: /b.js
43 | ////[|moment;|]
44 |
45 | goTo.file("/b.js");
46 | verify.importFixAtPosition([
47 | `import moment from "moment";
48 |
49 | moment;`
50 | ]);
51 | ```
52 |
53 | ### Formatting
54 |
55 |
56 | [0]: /src/testRunner/fourslashRunner.ts
57 | [1]: /tests/cases/fourslash
58 | [2]: /src/testRunner/runner.ts
59 | [3]: /src/harness/fourslash.ts
60 | [4]:
61 | [5]:
62 | [5]:
63 |
64 |
--------------------------------------------------------------------------------
/systems/testing/screenshots/diff.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/TypeScript-Compiler-Notes/31425672133e15f4e61f52a0f541d060f239e915/systems/testing/screenshots/diff.png
--------------------------------------------------------------------------------
/systems/testing/units.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/TypeScript-Compiler-Notes/31425672133e15f4e61f52a0f541d060f239e915/systems/testing/units.md
--------------------------------------------------------------------------------
/systems/vscode/README.md:
--------------------------------------------------------------------------------
1 | ### VS Code + TypeScript
2 |
3 | VS Code has three extensions related to TypeScript:
4 |
5 | - `extensions/typescript` - this is an `npm install`'d version of TypeScript.
6 | - `extensions/typescript-basics` - this is a extension which provides
7 | [language grammars and defines the language of TypeScript](https://github.com/microsoft/vscode/commit/e23c58b3aba76f25bb99400619d39f285eeec9e1#diff-cdbcc33fea0f5bd15137cf1750d69776)
8 | inside VS Code
9 | - `extensions/typescript-language-features` - this extends the TypeScript language support with commands,
10 | auto-complete et al.
11 |
12 | ### [`typescript-language-features`](https://github.com/microsoft/vscode/tree/master/extensions/typescript-language-features)
13 |
14 | A large amount of the work happens in the [`TypeScriptServiceClient`][1] which is the VS Code side of the
15 | TSServer.
16 |
17 | [1]:
18 | https://github.com/microsoft/vscode/blob/master/extensions/typescript-language-features/src/typescriptServiceClient.ts#L75
19 |
--------------------------------------------------------------------------------