diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 0ba4b8fc..9f5f83a1 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -1,4 +1,4 @@ -const tsFilePattern = '**/*.ts'; +const tsFilePattern = './src/**/*.ts'; module.exports = { root: true, env: { @@ -13,7 +13,6 @@ module.exports = { ecmaVersion: 2020, requireConfigFile: false, sourceType: 'module', - extraFileExtensions: ['.mjs', '.cjs'], babelOptions: { parserOpts: { plugins: ['importAssertions'] @@ -39,7 +38,7 @@ module.exports = { 'prettier' ], rules: { - 'prettier/prettier': 2, + '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }], '@typescript-eslint/no-explicit-any': ['error', { ignoreRestArgs: true }], '@typescript-eslint/explicit-module-boundary-types': 'error', '@typescript-eslint/no-namespace': ['error', { allowDeclarations: true }], diff --git a/jest.config.cjs b/jest.config.cjs deleted file mode 100644 index 39a99fd4..00000000 --- a/jest.config.cjs +++ /dev/null @@ -1,120 +0,0 @@ -const testRegex = [ - 'src/lib/alt/(.*)/__test__/test.ts', - 'src/lib/distributions/beta/__test__/.*.test.ts', - 'src/lib/distributions/binomial/__test__/.*.test.ts', - 'src/lib/distributions/binomial-negative/__test__/.*.test.ts', - 'src/lib/distributions/cauchy/__test__/.*.test.ts', - 'src/lib/distributions/chi-2/__test__/.*.test.ts', - 'src/lib/distributions/exp/__test__/.*.test.ts', - 'src/lib/distributions/f-distro/__test__/.*.test.ts', - 'src/lib/distributions/gamma/__test__/.*.test.ts', - 'src/lib/distributions/geometric/__test__/.*.test.ts', - 'src/lib/distributions/hypergeometric/__test__/.*.test.ts', - 'src/lib/distributions/logis/__test__/.*.test.ts', - 'src/lib/distributions/lognormal/__test__/.*.test.ts', - 'src/lib/distributions/multinom/__test__/.*.test.ts', - 'src/lib/distributions/normal/__test__/.*.test.ts', - 'src/lib/distributions/poisson/__test__/.*.test.ts', - 'src/lib/distributions/signrank/__test__/.*.test.ts', - 'src/lib/distributions/student-t/__test__/.*.test.ts', - 'src/lib/distributions/tukey/__test__/.*.test.ts', - 'src/lib/distributions/uniform/__test__/.*.test.ts', - 'src/lib/distributions/weibull/__test__/.*.test.ts', - 'src/lib/distributions/wilcoxon/__test__/.*.test.ts', - 'src/lib/rng/__test__/test.ts', - 'src/lib/rng/knuth-taocp/__test__/test.ts', - 'src/lib/rng/knuth-taocp-2002/__test__/test.ts', - 'src/lib/rng/lecuyer-cmrg/__test__/test.ts', - 'src/lib/rng/marsaglia-multicarry/__test__/test.ts', - 'src/lib/rng/mersenne-twister/__test__/test.ts', - 'src/lib/rng/normal/(.*)/__test__/test.ts', - 'src/lib/rng/super-duper/__test__/test.ts', - 'src/lib/rng/wichman-hill/__test__/test.ts', - 'src/lib/special/bessel/(.*)/__test__/test.ts', - 'src/lib/special/beta/__test__/.*.test.ts', - 'src/lib/special/choose/__test__/.*.test.ts', - 'src/lib/special/gamma/__test__/.*.test.ts' -]; - -const collectCoverageFrom = [ - 'src/lib/alt/**/*.ts', - 'src/lib/distributions/beta/*.ts', - 'src/lib/distributions/binomial/*.ts', - 'src/lib/distributions/binomial-negative/*.ts', - 'src/lib/distributions/cauchy/*.ts', - 'src/lib/distributions/chi-2/*.ts', - 'src/lib/distributions/exp/*.ts', - 'src/lib/distributions/f-distro/*.ts', - 'src/lib/distributions/gamma/*.ts', - 'src/lib/distributions/geometric/*.ts', - 'src/lib/distributions/hypergeometric/*.ts', - 'src/lib/distributions/logis/*.ts', - 'src/lib/distributions/lognormal/*.ts', - 'src/lib/distributions/multinom/*.ts', - 'src/lib/distributions/normal/*.ts', - 'src/lib/distributions/poisson/*.ts', - 'src/lib/distributions/signrank/*.ts', - 'src/lib/distributions/student-t/*.ts', - 'src/lib/distributions/tukey/*.ts', - 'src/lib/distributions/uniform/*.ts', - 'src/lib/distributions/weibull/*.ts', - 'src/lib/distributions/wilcoxon/*.ts', - 'src/lib/r-func.ts', - 'src/lib/index.ts', - 'src/lib/trigonometry/*.ts', - 'src/lib/stirling/index.ts', - 'src/lib/special/**/*.ts', - // - 'src/lib/rng/**/*.ts', - 'src/packages/common/logger.ts' -]; - -module.exports = { - bail: true, - automock: false, - collectCoverage: true, - maxWorkers: '50%', - collectCoverageFrom, - coveragePathIgnorePatterns: ['node_modules', 'test', 'doc.ts', 'IRandom.ts', 'IBesselRC.ts'], - coverageDirectory: 'coverage', - coverageProvider: 'babel', //"v8" is still experimental, but use "v8" for walk through debugging - //coverageProvider: 'v8', //"v8" is still experimental, but use "v8" for walk through debugging - coverageReporters: ['json', 'lcov', 'text', 'clover'], - preset: 'ts-jest', - testEnvironment: 'node', - verbose: true, - cacheDirectory: '.jest-cache', - testPathIgnorePatterns: ['/esm/', '/commonjs/', '/types/'], - //testMatch: ['**/__tests__/**/*.[t]s?(x)', '**/?(*.)+(spec|test).[t]s?(x)'], - testRegex, - transform: { - '\\.test\\.ts$': [ - 'ts-jest', - { - compiler: 'typescript', - tsconfig: 'tsconfig.json', - diagnostics: { - ignoreCodes: [151001] - } - } - ] - }, - moduleNameMapper: { - '^@dist/(.*)$': '/src/lib/distributions/$1', - '^@common/(.*)$': [ - '/src/packages/common/$1', - '/src/lib/common/$1', - '/src/packages/__test__/$1' - ], - '^@special/(.*)$': '/src/lib/special/$1', - '^@trig/(.*)$': '/src/lib/trigonometry/$1', - '^@rng/(.*)$': '/src/lib/rng/$1', - '^@lib/(.*)$': '/src/lib/$1', - '^lib/(.*)$': '/src/lib/$1' - }, - setupFiles: ['/src/packages/__test__/jest-ext.d.ts'], - setupFilesAfterEnv: [ - '/src/packages/__test__/jest-extension.ts', - '/src/packages/__test__/mock-of-debug.ts' - ] -}; diff --git a/notes/'this'-in-TypeScript.md b/notes/'this'-in-TypeScript.md new file mode 100644 index 00000000..53fbb895 --- /dev/null +++ b/notes/'this'-in-TypeScript.md @@ -0,0 +1,135 @@ +## Introduction +The `this` keyword in JavaScript (and thus TypeScript) behaves differently than it does in many other languages. This can be very surprising, especially for users of other languages that have certain intuitions about how `this` should work. + +This page will teach you how to recognize and diagnose problems with `this` in TypeScript, and describes several solutions and their respective trade-offs. + +## Typical Symptoms and Risk Factors +Typical symptoms of a lost `this` context include: + * A class field (`this.foo`) is `undefined` when some other value was expected + * The value `this` points to the global `window` object instead of the class instance (non-strict mode) + * The value `this` points `undefined` instead of the class instance (strict mode) + * Invoking a class method (`this.doBar()`) fails with the error "TypeError: undefined is not a function", "Object doesn't support property or method 'doBar'", or "this.doBar is not a function" + +These things often happen in certain coding patterns: + * Event listeners, e.g. `window.addEventListener('click', myClass.doThing);` + * Promise resolution, e.g. `myPromise.then(myClass.theNextThing);` + * Library event callbacks, e.g. `$(document).ready(myClass.start);` + * Functional callbacks, e.g. `someArray.map(myClass.convert)` + * Classes in ViewModel-type libraries, e.g. `
` + * Functions in options bags, e.g. `$.ajax(url, { success: myClass.handleData })` + +## What is `this` in JavaScript? +Much has been written about the hazards of `this` in JavaScript. See [this page](http://www.quirksmode.org/js/this.html), [this one](http://javascriptissexy.com/understand-javascripts-this-with-clarity-and-master-it/), or [this other one](http://bjorn.tipling.com/all-this). + +When a function is invoked in JavaScript, you can follow these steps to determine what `this` will be (these rules are in priority order): + * If the function was the result of a call to `function#bind`, `this` will be the argument given to `bind` + * If the function was invoked in the form `foo.func()`, `this` will be `foo` + * If in strict mode, `this` will be `undefined` + * Otherwise, `this` will be the global object (`window` in a browser) + +These rules can result in some counter-intuitive behavior. For example: +```ts +class Foo { + x = 3; + print() { + console.log('x is ' + this.x); + } +} + +var f = new Foo(); +f.print(); // Prints 'x is 3' as expected + +// Use the class method in an object literal +var z = { x: 10, p: f.print }; +z.p(); // Prints 'x is 10' + +var p = z.p; +p(); // Prints 'x is undefined' +``` + +## Red Flags for `this` +The biggest red flag you can keep in mind is *the use of a class method without immediately invoking it*. Any time you see a class method being *referenced* without being *invoked* as part of that same expression, `this` might be incorrect. + +Examples: +```ts +var x = new MyObject(); +x.printThing(); // SAFE, method is invoked where it is referenced + +var y = x.printThing; // DANGER, invoking 'y()' may not have correct 'this' + +window.addEventListener('click', x.printThing, 10); // DANGER, method is not invoked where it is referenced + +window.addEventListener('click', () => x.printThing(), 10); // SAFE, method is invoked in the same expression +``` + +## Fixes +There are several ways to correctly keep your `this` context. + +### Use Instance Functions +Instead of using a *prototype* method, the default for methods in TypeScript, you can use an *instance arrow function* to define a class member: +```ts +class MyClass { + private status = "blah"; + + public run = () => { // <-- note syntax here + alert(this.status); + } +} +var x = new MyClass(); +$(document).ready(x.run); // SAFE, 'run' will always have correct 'this' +``` + + * Good/bad: This creates an additional closure per method per instance of the class. If this method is usually only used in regular method calls, this is overkill. However, if it's used a lot in callback positions, it's more efficient for the class instance to capture the `this` context instead of each call site creating a new closure upon invoke. + * Good: Impossible for external callers to forget to handle `this` context + * Good: Typesafe in TypeScript + * Good: No extra work if the function has parameters + * Bad: Derived classes can't call base class methods written this way using `super` + * Bad: The exact semantics of which methods are "pre-bound" and which aren't create an additional non-typesafe contract between the class and its consumers + +### Local Fat Arrow +In TypeScript (shown here with some dummy parameters for explanatory reasons): + +```ts +var x = new SomeClass(); +someCallback((n, m) => x.doSomething(n, m)); +``` + + * Good/bad: Opposite memory/performance trade-off compared to instance functions + * Good: In TypeScript, this has 100% type safety + * Good: Works in ECMAScript 3 + * Good: You only have to type the instance name once + * Bad: You'll have to type the parameters twice + * Bad: Doesn't work with variadic ('rest') parameters + +### Function.bind +```ts +var x = new SomeClass(); +// SAFE: Functions created from function.bind always preserve 'this' +window.setTimeout(x.someMethod.bind(x), 100); +``` + + * Good/bad: Opposite memory/performance trade-off compared to using instance functions + * Good: No extra work if the function has parameters + * Bad: In TypeScript, this currently has no type safety + * Bad: Only available in [ECMAScript 5](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind) or newer + * Bad: You have to type the instance name twice + +### Specify type of `this` in function signature +See details [here](https://www.typescriptlang.org/docs/handbook/functions.html#this-parameters). + +```ts +interface SomeEvent { + cancelable: boolean; + preventDefault(): void; +} + +function eventHandler(this: SomeEvent) { + if (this.cancelable) { + this.preventDefault(); + } + // ... +} +``` + + * Good: The function has type information of the context it is supposed to run in, which is helpful in type checking and IDE completion + * Bad: The syntax of having `this` type declaration among function arguments might be confusing for developers at reading-time diff --git a/notes/API-Breaking-Changes.md b/notes/API-Breaking-Changes.md new file mode 100644 index 00000000..fc2cb530 --- /dev/null +++ b/notes/API-Breaking-Changes.md @@ -0,0 +1,301 @@ +# TypeScript 5.3 + +- The `tsserverlibrary.js` entrypoint is now a thin wrapper around the normal `typescript.js` entrypoint. It's recommended to switch to the latter where possible. If you were relying on being able to load `tsserverlibrary.js` in a non-CJS context (e.g., as a browser global), `tsserverlibrary.js` will throw, as it's unable to generically load another script into the page; you should switch to using `typescript.js`. + +# TypeScript 5.1 + +- The TypeScript package now targets ES2020 and requires Node 14.17 or newer. Note that Node 14 is EOL at the end of April 2023. +- `Occurrences` is request handling on `tsserver` and `LanguageService .getOccurrencesAtPosition` are removed now that they have been deprecated for a long time. Use `documentHighlights` request on `tsserver` and `LanguageService.getDocumentHighlights` instead. + + +# TypeScript 5.0 + +- TypeScript is now itself implemented using modules (though, the package still contains bundled outputs). + - The exported API is no longer defined as a "configurable" object, so operations which attempt to modify the package at runtime such as `const ts = require("ts"); ts.readJson = ...` will throw. + - The output files have changed significantly; if you are patching TypeScript, you will definitely need to change your patches. +- `typescriptServices.js` has been removed; this file was identical to `typescript.js`, the entrypoint for our npm package. +- `protocol.d.ts` is no longer included in the package; use `tsserverlibrary.d.ts`'s `ts.server.protocol` namespace instead. + - Some elements of the protocol are not actually exported by the `ts.server.protocol` namespace, but were emitted in the old `protocol.d.ts` file, and may need to be accessed off of the `ts` namespace instead. See https://github.com/microsoft/vscode/pull/163365 for an potential way to minimize changes to protocol-using codebases. +- The TypeScript package now targets ES2018 and requires Node 12.20 or newer. Prior to 5.0, our package targeted ES5 syntax and the ES2015 library. +- `ts.Map`, `ts.Set`, `ts.ESMap`, `ts.Iterator`, and associated types have been removed. The native `Map`, `Set`, `Iterator` and associated types should be used instead. +- The `ts.Collection` and `ts.ReadonlyCollection` types have been removed. These types were unused in our public API, and were declared with the old `Map`/`Set` types (also removed in 5.0). +- The `ts.Push` type has been removed. This type was only used twice in our API, and its uses have been replaced with arrays for consistency with other parts of our API. +- `BuilderProgramHost` no longer requires method `useCaseSensitiveFileNames` since its used from `program`. +- The TypeScript compiler is now compiled with `strictFunctionTypes`; to allow this, certain public AST visitor APIs have been modified to better reflect their underlying guarantees, as well as various corrections. The resulting API should be one that is more compatible with projects which also enable `strictFunctionTypes` (a recommended option enabled by `strict`). + - The `VisitResult` type is no longer `undefined` by default; if you have written `VisitResult`, you may need to rewrite it as `VisitResult` to reflect that your visitor may return undefined. + - Visitor-using APIs now correctly reflect the type of the output, including whether it passed a given type guard test, and whether or not it may be undefined. In order to get the type you expect, you may need to pass a `test` parameter to verify your expectations and then check the result for `undefined` (or, modify your visitor to return a more specific type). +- `typingOptions` along with its property `enableAutoDiscovery` which was deprecated for a long time is not supported any more in `tsconfig.json` and `jsconfig.json`. Use `typeAcquisition` in the config instead. +- This release removes many long-deprecated parts of our public API, including (but not limited to): + - The top-level Node factory functions (deprecated since TS 4.0) such as `ts.createIdentifier`; use the factory provided in your `TransformationContext` or `ts.factory` instead. + - The `isTypeAssertion` function (deprecated since TS 4.0); use `isTypeAssertionExpression`. + - The overloads of `createConstructorTypeNode` and `updateConstructorTypeNode` which do not accept modifiers (deprecated since TS 4.2). + - The overloads of `createImportTypeNode` and `updateImportTypeNode` which do not accept assertions (deprecated since TS 4.6). + - The overloads of `createTypeParameterDeclaration` and `updateTypeParameterDeclaration` which do not accept modifiers (deprecated since TS 4.6). + - Node properties and factory function overloads which predate the merger of decorators and modifiers (deprecated since TS 4.8). + +# TypeScript 4.9 + +## `substitute` Replaced With `constraint` on `SubstitutionType`s + +As part of an optimization on substitution types, `SubstitutionType` objects no longer contain the `substitute` property representing the effective substitution (usually an intersection of the base type and the implicit constraint) - instead, they just contain the `constraint` property. + +For more details, [read more on the original pull request](https://github.com/microsoft/TypeScript/pull/50397). + +# TypeScript 4.8 + +## Decorators are placed on `modifiers` on TypeScript's Syntax Trees + +The current direction of decorators in TC39 means that TypeScript will have to handle a break in terms of placement of decorators. +Previously, TypeScript assumed decorators would always be placed prior to all keywords/modifiers. +For example + +```ts +@decorator +export class Foo { + // ... +} +``` + +Decorators as currently proposed do not support this syntax. +Instead, the `export` keyword must precede the decorator. + +```ts +export @decorator class Foo { + // ... +} +``` + +Unfortunately, TypeScript's trees are *concrete* rather than *abstract*, and our architecture expects syntax tree node fields to be entirely ordered before or after each other. +To support both legacy decorators and decorators as proposed, TypeScript will have to gracefully parse, and intersperse, modifiers and decorators. + +To do this, it exposes a new type alias called `ModifierLike` which is a `Modifier` or a `Decorator`. + +```ts +export type ModifierLike = Modifier | Decorator; +``` + +Decorators are now placed in the same field as `modifiers` which is now a `NodeArray` when set, and the entire field is deprecated. + +```diff +- readonly modifiers?: NodeArray | undefined; ++ /** ++ * @deprecated ... ++ * Use `ts.canHaveModifiers()` to test whether a `Node` can have modifiers. ++ * Use `ts.getModifiers()` to get the modifiers of a `Node`. ++ * ... ++ */ ++ readonly modifiers?: NodeArray | undefined; +``` + +All existing `decorators` properties have been marked as deprecated and will always be `undefined` if read. +The type has also been changed to `undefined` so that existing tools know to handle them correctly. + +```diff +- readonly decorators?: NodeArray | undefined; ++ /** ++ * @deprecated ... ++ * Use `ts.canHaveDecorators()` to test whether a `Node` can have decorators. ++ * Use `ts.getDecorators()` to get the decorators of a `Node`. ++ * ... ++ */ ++ readonly decorators?: undefined; +``` + +To avoid all deprecation warnings and other issues, TypeScript now exposes four new functions. +There are individual predicates for testing whether a node has support modifiers and decorators, along with respective accessor functions for grabbing them. + +```ts +function canHaveModifiers(node: Node): node is HasModifiers; +function getModifiers(node: HasModifiers): readonly Modifier[] | undefined; + +function canHaveDecorators(node: Node): node is HasDecorators; +function getDecorators(node: HasDecorators): readonly Decorator[] | undefined; +``` + +As an example of how to access modifiers off of a node, you can write + +```ts +const modifiers = canHaveModifiers(myNode) ? getModifiers(myNode) : undefined; +``` + +With the note that each call to `getModifiers` and `getDecorators` may allocate a new array. + +For more information, see changes around + +* [the restructuring of our tree nodes](https://github.com/microsoft/TypeScript/pull/49089) +* [the deprecations](https://github.com/microsoft/TypeScript/pull/50343) +* [exposing the predicate functions](https://github.com/microsoft/TypeScript/pull/50399) + +# TypeScript 4.7 + +- `resolveTypeReferenceDirectives` (both the services and global ts version) now accept an array of `FileReference`s as a first argument. If you reimplement `resolveTypeReferenceDirectives`, you need to handle both the `string[]` and `FileReference[]` cases now. + +# TypeScript 4.5 + +- `factory.createImportSpecifier` and `factory.updateImportSpecifier` now take an `isTypeOnly` parameter: + + ```diff + - createImportSpecifier(propertyName: Identifier | undefined, name: Identifier): ImportSpecifier; + + createImportSpecifier(isTypeOnly: boolean, propertyName: Identifier | undefined, name: Identifier): ImportSpecifier; + - updateImportSpecifier(node: ImportSpecifier, propertyName: Identifier | undefined, name: Identifier): ImportSpecifier; + + updateImportSpecifier(node: ImportSpecifier, isTypeOnly: boolean, propertyName: Identifier | undefined, name: Identifier): ImportSpecifier; + ``` + + You can read more about this change at the [implementing PR](https://github.com/microsoft/TypeScript/pull/45998). + +# TypeScript 4.2 + +- `visitNode`'s `lift` Takes a `readonly Node[]` Instead of a `NodeArray` + + The `lift` function in the `visitNode` API now takes a `readonly Node[]`. + You can [see details of the change here](https://github.com/microsoft/TypeScript/pull/42000). + + +# TypeScript 4.1 + +- Type Arguments in JavaScript Are Not Parsed as Type Arguments + + Type arguments were already not allowed in JavaScript, but in TypeScript 4.1, the parser will parse them in a more spec-compliant way. + So when writing the following code in a JavaScript file: + + ```ts + f(100) + ``` + + TypeScript will parse it as the following JavaScript: + + ```js + (f < T) > (100) + ``` + + This may impact you if you were leveraging TypeScript's API to parse type constructs in JavaScript files, which may have occurred when trying to parse Flow files. + + [See more details here](https://github.com/microsoft/TypeScript/pull/36673). + +# TypeScript 4.0 + +- TypeScript provides a set of "factory" functions for producing syntax tree nodes; however, TypeScript 4.0 provides a new node factory API. For TypeScript 4.0 we've made the decision to deprecate these older functions in favor of the new ones. For more details, [read up on the relevant pull request for this change](https://github.com/microsoft/TypeScript/pull/35282). + +- `TupleTypeNode.elementTypes` renamed to `TupleTypeNode.elements`. +- `KeywordTypeNode` is no longer used to represent `this` and `null` types. `null` now gets a `LiteralTypeNode`, `this` now always gets a `ThisTypeNode`. +- `TypeChecker.typeToTypeNode` now correctly produces a `LiteralTypeNode` for `true` and `false` types, which matches the behavior in the parser. Prior to this the checker was incorrectly returning the `true` and `false` tokens themselves, which are indistinguishable from expressions when traversing a tree. + +# TypeScript 3.8 + +- The mutable property `disableIncrementalParsing` has been removed. It was untested and, at least on GitHub, unused by anyone. Incremental parsing can no longer be disabled. + +# TypeScript 3.7 + +- the `typeArguments` property has been removed from the `TypeReference` interface, and the `getTypeArguments` method on `TypeChecker` instances should be used instead. This change was necessary to defer resolution of type arguments in order to support [recursive type references](https://github.com/microsoft/TypeScript/pull/33050). + + As a workaround, you can define a helper function to support multiple versions of TypeScript. + + ```ts + function getTypeArguments(checker: ts.TypeChecker, typeRef: ts.TypeReference) { + return checker.getTypeArguments?.(typeRef) ?? (typeRef as any).typeArguments; + } + ``` + + +# TypeScript 3.1 + +- `SymbolFlags.JSContainer` has been renamed to `SymbolFlags.Assignment` to reflect that Typescript now supports expando assignments to functions. + +# TypeScript 3.0 + +- The deprecated internal method `LanguageService#getSourceFile` has been removed. See [#24540](https://github.com/microsoft/TypeScript/pull/24540). +- The deprecated function `TypeChecker#getSymbolDisplayBuilder` and associated interfaces have been removed. See [#25331](https://github.com/Microsoft/TypeScript/pull/25331). The emitter and node builder should be used instead. +- The deprecated functions `escapeIdentifier` and `unescapeIdentifier` have been removed. Due to changing how the identifier name API worked in general, they have been identity functions for a few releases, so if you need your code to behave the same way, simply removing the calls should be sufficient. Alternatively, the typesafe `escapeLeadingUnderscores` and `unescapeLeadingUnderscores` should be used if the types indicate they are required (as they are used to convert to or from branded `__String` and `string` types). +- The `TypeChecker#getSuggestionForNonexistentProperty`, `TypeChecker#getSuggestionForNonexistentSymbol`, and `TypeChecker#getSuggestionForNonexistentModule` methods have been made internal, and are no longer part of our public API. See [#25520](https://github.com/Microsoft/TypeScript/pull/25520). + +# TypeScript 2.8 +- `getJsxIntrinsicTagNames` has been removed and replaced with `getJsxIntrinsicTagNamesAt`, which requires a node to use as the location to look up the valid intrinsic names at (to handle locally-scoped JSX namespaces). + +# TypeScript 2.6 + +- Some services methods (`getCompletionEntryDetails` and `getCompletionEntrySymbols`) have additional parameters. Plugins that wrap the language service must pass these parameters along to the original implementation. See [#19507](https://github.com/Microsoft/TypeScript/pull/19507#issuecomment-340600363) + +# TypeScript 2.5 +- `Symbol.name`, `Symbol.getName()`, and `Identifier.text` are all now of type `__String`. This is a special branded string to help track where strings are appropriately escaped and prevent their misuse. `escapeIdentifier` and `unescapeIdentifier` has been renamed to `escapeLeadingUnderscores` and `unescapeLeadingUnderscores` and had their types updated accordingly. Deprecated versions of `escapeIdentifier` and `unescapeIdentifier` still exist with the old name and type signature, however they will be removed in a future version. See [#16915](https://github.com/Microsoft/TypeScript/issues/16915). + +# TypeScript 2.4 + +- The following types/namespaces are now string enums: `ts.Extension`, `ts.ScriptElementKind`, `ts.HighlightSpanKind`, `ts.ClassificationTypeNames`, `protocol.CommandTypes`, `protocol.IndentStyle`, `protocol.JsxEmit`, `protocol.ModuleKind`, `protocol.ModuleResolutionKind`, `protocol.NewLineKind`, and `protocol.ScriptTarget`. Also, `ts.CommandNames` is now an alias for `protocol.CommandTypes`. See [#15966](https://github.com/Microsoft/TypeScript/pull/15966) and [#16425](https://github.com/Microsoft/TypeScript/pull/16425). + +- The type `EnumLiteralType` was removed and `LiteralType` is used instead. `LiteralType` also replaces `.text` with a `.value` which may be either a number or string. See [String valued members in enums](https://github.com/Microsoft/TypeScript/pull/15486). + +- `Declaration` does not have a `name` property. TypeScript now recognize assignments in .js files as declarations in certain contexts, e.g. `func.prototype.method = function() {..}` will be a declaration of member `method` on `func`. As a result `Declaration` is not guaranteed to have a `name` property as before. A new type was introduced `NamedDeclaration` to take the place of `Declaration`, and `Declaration` moved to be the base type of both `NamedDeclaration` and `BinaryExpression`. +Casting to `NamedDeclaration` should be safe for non .js declarations. +See [#15594](https://github.com/Microsoft/TypeScript/pull/15594) for more details. + +# TypeScript 2.2 + +- `ts.Map` is now a native `Map` or a shim. This affects the `SymbolTable` type, exposed by `Symbol.members`, `Symbol.exports`, and `Symbol.globalExports`. + +# TypeScript 2.1 + +- `ParseConfigHost` now requires a new member `readFile` to support [configuration inheritance](https://github.com/Microsoft/TypeScript/pull/9941). + +# TypeScript 1.9 + +- [`LanguageService.getSourceFile` has been removed](https://github.com/Microsoft/TypeScript/pull/7584); `LanguageService.getProgram().getSourceFile` should be used instead. + +# TypeScript 1.7 + +- `ts.parseConfigFile` has been renamed to `ts.parseJsonConfigFileContent` + +# TypeScript 1.6 + +### CompilerHost interface change (comparing to TypeScript 1.6 beta) +- return type of `CompilerHost.resolveModuleNames` was changed from `string[]` to `ResolvedModule[]`. Extra optional property `isExternalLibraryImport` in [ResolvedModule](https://github.com/Microsoft/TypeScript/blob/026632bca8b13a7f180ae8226e109d296480ddad/src/compiler/types.ts#L2274) interface denotes if `Program` should apply some particular set of policies to the resolved file. For example if Node resolver has resolved non-relative module name to the file in 'node_modules', then this file: + - should be a 'd.ts' file + - should be an external module + - should not contain tripleslash references. + + Rationale: files containing external typings should not pollute global scope (to avoid conflicts between different versions of the same package). Also such files should never be added to the list of compiled files (otherwise compiled .ts file might overwrite actual .js file with implementation of the package) + +# TypeScript 1.5 + +### Program interface changes +- `TypeChecker.emitFiles` is no longer available; use `Program.emit` instead. +- Getting diagnostics are now all centralized on Program, + - for Syntactic diagnostics for a single file use: `Program.getSyntacticDiagnostics(sourceFile)` + - for Syntactic diagnostics for all files use: `Program.getSyntacticDiagnostics()` + - for Semantic diagnostics for a single file use: `Program.getSemanticDiagnostics(sourceFile)` + - for Semantic diagnostics for all files use: `Program.getSemanticDiagnostics()` + - for compiler options and global diagnostics use: `Program.getGlobalDiagnostics()` +> Tip: use ts.getPreEmitDiagnostics(program) to get syntactic, semantic, and global diagnostics for all files + +### All usages of 'filename' and 'Filename' changed to 'fileName' and 'FileName' +Here are the details: +- `CompilerHost.getDefaultLibFilename` => `CompilerHost.getDefaultLibFileName` +- `SourceFile.filename` => `SourceFile.fileName` +- `FileReference.filename` => `FileReference.fileName` +- `LanguageServiceHost.getDefaultLibFilename` => `LanguageServiceHost.getDefaultLibFileName` +- `LanguageServiceShimHost.getDefaultLibFilename` => `LanguageServiceShimHost.getDefaultLibFileName` + + +The full list of APIs can be found in [this commit](https://github.com/Microsoft/TypeScript/commit/de13648c9f87e0da272f5ed14767afb2c8788322) + +### The `syntacticClassifierAbsent` parameter for the Classifier.getClassificationsForLine is now required +See [Pull Request #2051](https://github.com/Microsoft/TypeScript/pull/2051) for more details. + +### Changes to TextChange +`TextChange.start` and `TextChange.length` became properties instead of methods. + +### SourceFile.getLineAndCharacterFromPosition +`SourceFile.getLineAndCharacterFromPosition` became `SourceFile.getLineAndCharacterOfPosition` + +### APIs made internal as they are not intended for use outside of the compiler +We did some cleanup to the public interfaces, here is the full list of changes: +- Commit [2ee134c6b3c0ec](https://github.com/Microsoft/TypeScript/commit/2ee134c6b3c0ece87591e8abc9db833ebb7675cc) +- Commit [35dde28d44122c](https://github.com/Microsoft/TypeScript/commit/35dde28d44122c90aaae7695f56bf22c1d848486) +- Commit [c9ef4db99ac93bb1c166a](https://github.com/Microsoft/TypeScript/commit/c9ef4db99ac93bb1c166aa9af495453eeceea279) +* Commit [b4e5d5b0b460cc88a10db](https://github.com/Microsoft/TypeScript/commit/b4e5d5b0b460cc88a10dbfdb0a935fb33b534ab2) + + +### `typescript_internal.d.ts` and `typescriptServices_internal.d.ts` have been removed + +The two files exposed helpers in the past that were not part of the supported TypeScript API. If you were using any of these APIs please file an issue to re-expose them; requests for exposing helper APIs will be triaged on a case-by-case basis. + +For more information please see the [full change](https://github.com/Microsoft/TypeScript/pull/2692). diff --git a/notes/All-The-Bots.md b/notes/All-The-Bots.md new file mode 100644 index 00000000..9fc319f9 --- /dev/null +++ b/notes/All-The-Bots.md @@ -0,0 +1,17 @@ +This is a list of the services that post as typescript-bot. + +## TypeScript repo + +- [GitHub Actions - close issues](https://github.com/microsoft/TypeScript/blob/main/.github/workflows/close-issues.yml) +- [GitHub Actions - PR replies for modified files](https://github.com/microsoft/TypeScript/blob/main/.github/workflows/pr-modified-files.yml) +- https://github.com/microsoft/typescript-bot-test-triggerer -- runs on the Azure Function typescriptbot-github, see [[Triggering TypeScript Bot]] -- responds to "test this" messages from team members. +- https://github.com/microsoft/Typescript-repos-automation -- runs on the Azure Function TypeScriptReposAutomation -- more simple reactions to labels. +- https://github.com/microsoft/TypeScript-Twoslash-Repro-Action -- run `tsrepro` and bisects: https://github.com/microsoft/TypeScript/blob/main/.github/workflows/twoslash-repros.yaml +- https://github.com/microsoft/typescript-error-deltas -- produces PR comments showing new errors caused by PRs + +## Definitely Typed repo + +- https://github.com/DefinitelyTyped/dt-mergebot -- runs on the Azure Function DTMergebot -- posts status comments, adds labels, maintains board, merges PRs. +- https://github.com/microsoft/DefinitelyTyped-tools -- runs on the Azure Function types-publisher -- publishes packages +- https://github.com/microsoft/DefinitelyTyped-tools -- runs on the Azure Function dt-perf -- posts performance analysis (non-working) +- [DangerBotOSS](https://github.com/definitelytyped/definitelytyped/tree/main/.github/workflows/CI.yml) -- suggests missed exports (posts as DangerBotOSS, not typescript-bot) diff --git a/notes/Architectural-Overview.md b/notes/Architectural-Overview.md new file mode 100644 index 00000000..3d7eaaa1 --- /dev/null +++ b/notes/Architectural-Overview.md @@ -0,0 +1,15 @@ +## Layer Overview +## Data Structures + +Moved to [the glossary](https://github.com/microsoft/TypeScript-Compiler-Notes/blob/main/GLOSSARY.md) of the complier-notes repo. + +## Overview of the compilation process + +Moved to the root readme of the [complier-notes repo](https://github.com/microsoft/TypeScript-Compiler-Notes). + +## Terminology + +### **Full Start/Token Start** +### **Trivia** + +See [the Scanner](https://github.com/microsoft/TypeScript-Compiler-Notes/blob/main/codebase/src/compiler/scanner.md) in the complier-notes repo. \ No newline at end of file diff --git a/notes/Blog-Post-Ideas.md b/notes/Blog-Post-Ideas.md new file mode 100644 index 00000000..75a14bc3 --- /dev/null +++ b/notes/Blog-Post-Ideas.md @@ -0,0 +1,42 @@ +**How-to guides for non-language features** + +* Use the npm package for xcopyable build scripts +* Use the watch flag for faster development +* Manage ///reference hell; keep files in correct order when using --out +* Combine external modules with browserify +* Use Angular with TypeScript +* Use knockout with TypeScript +* Use […] with TypeScript +* Guest blog: basarat explains grunt-ts +* Use .d.ts files for separate compilation +* How to use TypeScript with Sublime/Emacs/etc +* Common workflows with linters (JS and TS), minifiers, etc + +**Explorations** + +* Type inference in TypeScript (multi-part series) +* Object serialization in TypeScript (revivers for class prototypes, etc) + +**Deep dives (handbook updates?)** + +* Function overloading +* Classes +* Modules +* Enum and const enum +* Let and const + +**Why and How?** + +* Why are function parameter types bivariant? +* How do I handle `this` in my program? +* When should I use instance methods vs prototype methods? +* How do I write a definition file? Walk through an example +* Advanced version: Choosing between overloads/optional params, use `{}` instead of `any`, etc +* How do I convert a JavaScript file to TypeScript? Walk through an example +* Advanced performance optimizations for rest and optional arguments + +**Well-intentioned C# programmers** + +* Why can’t I declare an arbitrary indexer? +* What’s the deal with `typeof T` ? +* How do I do reflection? diff --git a/notes/Breaking-Changes.md b/notes/Breaking-Changes.md new file mode 100644 index 00000000..0e919202 --- /dev/null +++ b/notes/Breaking-Changes.md @@ -0,0 +1,3235 @@ +These changes list where implementation differs between versions as the spec and compiler are simplified and inconsistencies are corrected. + +> For breaking changes to the compiler/services API, please check the [[API Breaking Changes]] page. + +# TypeScript 4.9 + +## Better Types for `Promise.resolve` + +`Promise.resolve` now uses the `Awaited` type to unwrap Promise-like types passed to it. +This means that it more often returns the right `Promise` type, but that improved type can break existing code if it was expecting `any` or `unknown` instead of a `Promise`. +For more information, [see the original change](https://github.com/microsoft/TypeScript/pull/33074). + +## JavaScript Emit No Longer Elides Imports + +When TypeScript first supported type-checking and compilation for JavaScript, it accidentally supported a feature called import elision. +In short, if an import is not used as a value, or the compiler can detect that the import doesn't refer to a value at runtime, the compiler will drop the import during emit. + +This behavior was questionable, especially the detection of whether the import doesn't refer to a value, since it means that TypeScript has to trust sometimes-inaccurate declaration files. +In turn, TypeScript now preserves imports in JavaScript files. + +```js +// Input: +import { someValue, SomeClass } from "some-module"; + +/** @type {SomeType} */ +let val = someValue; + +// Previous Output: +import { someValue } from "some-module"; + +/** @type {SomeClass} */ +let val = someValue; + +// Current Output: +import { someValue, SomeClass } from "some-module"; + +/** @type {SomeType} */ +let val = someValue; +``` + +More information is available at [the implementing change](https://github.com/microsoft/TypeScript/pull/50404). + +## `exports` is Prioritized Over `typesVersions` + +Previously, TypeScript incorrectly prioritized the `typesVersions` field over the `exports` field when resolving through a `package.json` under `--moduleResolution node16`. +If this change impacts your library, you may need to add `types@` version selectors in your `package.json`'s `exports` field. + +```diff + { + "type": "module", + "main": "./dist/main.js" + "typesVersions": { + "<4.8": { ".": ["4.8-types/main.d.ts"] }, + "*": { ".": ["modern-types/main.d.ts"] } + }, + "exports": { + ".": { ++ "types@<4.8": "4.8-types/main.d.ts", ++ "types": "modern-types/main.d.ts", + "import": "./dist/main.js" + } + } + } +``` + +For more information, [see this pull request](https://github.com/microsoft/TypeScript/pull/50890). + +# TypeScript 4.8 + +## Unconstrained Type Parameters No Longer Assignable to `{}` in `strictNullChecks` + +Originally, the constraint of all type parameters in TypeScript was `{}` (the empty object type). +Eventually the constraint was changed to `unknown` which also permits `null` and `undefined`. +Outside of `strictNullChecks`, these types are interchangeable, but within `strictNullChecks`, `unknown` is not assignable to `{}`. + +In TypeScript 4.8, under `strictNullChecks`, the type-checker disables a type safety hole that was maintained for backwards-compatibility, where type parameters were considered to always be assignable to `{}`, `object`, and any other structured types with all-optional properties. + +```ts +function foo(x: T) { + const a: {} = x; + // ~ + // Type 'T' is not assignable to type '{}'. + + const b: object = x; + // ~ + // Type 'T' is not assignable to type 'object'. + + const c: { foo?: string, bar?: number } = x; + // ~ + // Type 'T' is not assignable to type '{ foo?: string | undefined; bar?: number | undefined; }'. +} +``` + +In such cases, you may need a type assertion on `x`, or a constraint of `{}` on `T`. + +```ts +function foo(x: T) { + // Works + const a: {} = x; + + // Works + const b: object = x; +} +``` + +This behavior can come up in calls to `Object.keys`: + +```ts +function keysEqual(x: T, y: T) { + const xKeys = Object.keys(x); + const yKeys = Object.keys(y); + + if (xKeys.length !== yKeys.length) return false; + for (let i = 0; i < xKeys.length; i++) { + if (xKeys[i] !== yKeys[i]) return false; + } + return true; +} +``` + +For the above, you might see an error message that looks like this: + +```ts +No overload matches this call. + Overload 1 of 2, '(o: {}): string[]', gave the following error. + Argument of type 'T' is not assignable to parameter of type '{}'. + Overload 2 of 2, '(o: object): string[]', gave the following error. + Argument of type 'T' is not assignable to parameter of type 'object'. +``` + +Appropriately performing runtime checks to narrow the type, or using a type-assertion, may be the best way to deal with these new errors. + +For more information, take a look at [the breaking PR here](https://github.com/microsoft/TypeScript/pull/48366). + +___________ + +
+ +See Changes for Older Releases + + +# TypeScript 4.7 + +## Stricter Spread Checks in JSX + +When writing a `...spread` in JSX, TypeScript now enforces stricter checks that the given type is actually an object. +As a results, values with the types `unknown` and `never` (and more rarely, just bare `null` and `undefined`) can no longer be spread into JSX elements. + +So for the following example: + +```tsx +import * as React from "react"; + +interface Props { + stuff?: string; +} + +function MyComponent(props: unknown) { + return
; +} +``` + +you'll now receive an error like the following: + +``` +Spread types may only be created from object types. +``` + +This makes this behavior more consistent with spreads in object literals. + +For more details, [see the change on GitHub](https://github.com/microsoft/TypeScript/pull/48570). + +## Stricter Checks with Template String Expressions + +When a `symbol` value is used in a template string, it will trigger a runtime error in JavaScript. + +```js +let str = `hello ${Symbol()}`; +// TypeError: Cannot convert a Symbol value to a string +``` + +As a result, TypeScript will issue an error as well; +however, TypeScript now also checks if a generic value that is constrained to a symbol in some way is used in a template string. + +```ts +function logKey(key: S): S { + // Now an error. + console.log(`${key} is the key`); + return key; +} + +function get(obj: T, key: K) { + // Now an error. + console.log(`Grabbing property '${key}'.`); + return obj[key]; +} +``` + +TypeScript will now issue the following error: + +``` +Implicit conversion of a 'symbol' to a 'string' will fail at runtime. Consider wrapping this expression in 'String(...)'. +``` + +In some cases, you can get around this by wrapping the expression in a call to `String`, just like the error message suggests. + +```ts +function logKey(key: S): S { + // Now an error. + console.log(`${String(key)} is the key`); + return key; +} +``` + +In others, this error is too pedantic, and you might not ever care to even allow `symbol` keys when using `keyof`. +In such cases, you can switch to `string & keyof ...`: + +```ts +function get(obj: T, key: K) { + // Now an error. + console.log(`Grabbing property '${key}'.`); + return obj[key]; +} +``` + +For more information, you can [see the implementing pull request](https://github.com/microsoft/TypeScript/pull/44578). + +## `readFile` Method is No Longer Optional on `LanguageServiceHost` + +If you're creating `LanguageService` instances, then provided `LanguageServiceHost`s will need to provide a `readFile` method. +This change was necessary to support the new `moduleDetection` compiler option. + +You can [read more on the change here](https://github.com/microsoft/TypeScript/pull/47495). + +## `readonly` Tuples Have a `readonly` `length` Property + +A `readonly` tuple will now treat its `length` property as `readonly`. +This was almost never witnessable for fixed-length tuples, but was an oversight which could be observed for tuples with trailing optional and rest element types. + +As a result, the following code will now fail: + +```ts +function overwriteLength(tuple: readonly [string, string, string]) { + // Now errors. + tuple.length = 7; +} +``` + +You can [read more on this change here](https://github.com/microsoft/TypeScript/pull/47717). + +# TypeScript 4.6 + +## Object Rests Drop Unspreadable Members from Generic Objects + +Object rest expressions now drop members that appear to be unspreadable on generic objects. +In the following example... + +```ts +class Thing { + someProperty = 42; + + someMethod() { + // ... + } +} + +function foo(x: T) { + let { someProperty, ...rest } = x; + + // Used to work, is now an error! + // Property 'someMethod' does not exist on type 'Omit'. + rest.someMethod(); +} +``` + +the variable `rest` used to have the type `Omit` because TypeScript would strictly analyze which other properties were destructured. +This doesn't model how `...rest` would work in a destructuring from a non-generic type because `someMethod` would typically be dropped as well. +In TypeScript 4.6, the type of `rest` is `Omit`. + +This can also come up in cases when destructuring from `this`. +When destructuring `this` using a `...rest` element, unspreadable and non-public members are now dropped, which is consistent with destructuring instances of a class in other places. + +```ts +class Thing { + someProperty = 42; + + someMethod() { + // ... + } + + someOtherMethod() { + let { someProperty, ...rest } = this; + + // Used to work, is now an error! + // Property 'someMethod' does not exist on type 'Omit'. + rest.someMethod(); + } +} +``` + +For more details, [see the corresponding change here](https://github.com/microsoft/TypeScript/pull/47078). + +## JavaScript Files Always Receive Grammar and Binding Errors + +Previously, TypeScript would ignore most grammar errors in JavaScript apart from accidentally using TypeScript syntax in a JavaScript file. +TypeScript now shows JavaScript syntax and binding errors in your file, such as using incorrect modifiers, duplicate declarations, and more. +These will typically be most apparent in Visual Studio Code or Visual Studio, but can also occur when running JavaScript code through the TypeScript compiler. + +You can explicitly turn these errors off by inserting a `// @ts-nocheck` comment at the top of your file. + +For more information, see the [first](https://github.com/microsoft/TypeScript/pull/47067) and [second](https://github.com/microsoft/TypeScript/pull/47075) implementing pull requests for these features. + +# TypeScript 4.5 + +## `lib.d.ts` Changes for TypeScript 4.5 + +TypeScript 4.5 contains changes to its built-in declaration files which may affect your compilation; +however, [these changes were fairly minimal](https://github.com/microsoft/TypeScript-DOM-lib-generator/issues/1143), and we expect most code will be unaffected. + +## Inference Changes from `Awaited` + +Because `Awaited` is now used in `lib.d.ts` and as a result of `await`, you may see certain generic types change that might cause incompatibilities. +This may cause issues when providing explicit type arguments to functions like `Promise.all`, `Promise.allSettled`, etc. + +Often, you can make a fix by removing type arguments altogether. + +```diff +- Promise.all(...) ++ Promise.all(...) +``` + +More involved cases will require you to replace a list of type arguments with a single type argument of a tuple-like type. + + +```diff +- Promise.all(...) ++ Promise.all<[boolean, boolean]>(...) +``` + +However, there will be occasions when a fix will be a little bit more involved, and replacing the types with a tuple of the original type arguments won't be enough. +[One example where this occasionally comes up](https://github.com/microsoft/TypeScript/issues/46651#issuecomment-959791706) is when an element is possibly a `Promise` or non-`Promise`. +In those cases, it's no longer okay to unwrap the underlying element type. + +```diff +- Promise.all(...) ++ Promise.all<[Promise | undefined, Promise | undefined]>(...) +``` + +## Template Strings Use `.concat()` + +Template strings in TypeScript previously just used the `+` operator when targeting ES3 or ES5; +however, this leads to some divergences between the use of `.valueOf()` and `.toString()` which ends up being less spec-compliant. +This is usually not noticeable, but is particularly important when using upcoming standard library additions like [Temporal](https://tc39.es/proposal-temporal/docs/). + +TypeScript now uses calls to `.concat()` on `strings`. +This gives code the same behavior regardless of whether it targets ES3 and ES5, or ES2015 and later. +Most code should be unaffected, but you might now see different results on values that define separate `valueOf()` and `toString()` methods. + +```ts +import moment = require("moment"); + +// Before: "Moment: Wed Nov 17 2021 16:23:57 GMT-0800" +// After: "Moment: 1637195037348" +console.log(`Moment: ${moment()}`); +``` + +More more information, [see the original issue](https://github.com/microsoft/TypeScript/issues/39744). + +## Compiler Options Checking at the Root of `tsconfig.json` + +It's an easy mistake to accidentally forget about the `compilerOptions` section in a `tsconfig.json`. +To help catch this mistake, in TypeScript 4.5, it is an error to add a top-level field which matches any of the available options in `compilerOptions` *without* having also defined `compilerOptions` in that `tsconfig.json`. + +## Restrictions on Assignability to Conditional Types + +TypeScript no longer allows types to be assignable to conditional types that use `infer`, or that are distributive. +Doing so previously often ended up causing major performance issues. +For more information, [see the specific change on GitHub](https://github.com/microsoft/TypeScript/pull/46429). + +# TypeScript 4.4 + +## `lib.d.ts` Changes for TypeScript 4.4 + +As with every TypeScript version, declarations for `lib.d.ts` (especially the declarations generated for web contexts), have changed. +You can consult [our list of known `lib.dom.d.ts` changes](https://github.com/microsoft/TypeScript-DOM-lib-generator/issues/1029#issuecomment-869224737) to understand what is impacted. + +## More-Compliant Indirect Calls for Imported Functions + +In earlier versions of TypeScript, calling an import from CommonJS, AMD, and other non-ES module systems would set the `this` value of the called function. +Specifically, in the following example, when calling `fooModule.foo()`, the `foo()` method will have `fooModule` set as the value of `this`. + +```ts +// Imagine this is our imported module, and it has an export named 'foo'. +let fooModule = { + foo() { + console.log(this); + } +}; + +fooModule.foo(); +``` + +This is not the way exported functions in ECMAScript are supposed to work when we call them. +That's why TypeScript 4.4 intentionally discards the `this` value when calling imported functions, by using the following emit. + +```ts +// Imagine this is our imported module, and it has an export named 'foo'. +let fooModule = { + foo() { + console.log(this); + } +}; + +// Notice we're actually calling '(0, fooModule.foo)' now, which is subtly different. +(0, fooModule.foo)(); +``` + +For more information, you can read up more [here](https://github.com/microsoft/TypeScript/pull/44624). + +## Using `unknown` in Catch Variables + +Users running with the `--strict` flag may see new errors around `catch` variables being `unknown` due to the new `--useUnknownForCatchVariables` flag, especially if the existing code assumes only `Error` values have been caught. +This often results in error messages such as: + +``` +Property 'message' does not exist on type 'unknown'. +Property 'name' does not exist on type 'unknown'. +Property 'stack' does not exist on type 'unknown'. +Object is of type 'unknown'. +``` + +To get around this, you can specifically add runtime checks to ensure that the thrown type matches your expected type. +Otherwise, you can just use a type assertion, add an explicit `: any` to your catch variable, or turn off `--useUnknownInCatchVariables`. + +## Broader Always-Truthy Promise Checks + +In prior versions, TypeScript introduced "Always Truthy Promise checks" to catch code where an `await` may have been forgotten; +however, the checks only applied to named declarations. +That meant that while this code would correctly receive an error... + +```ts +async function foo(): Promise { + return false; +} + +async function bar(): Promise { + const fooResult = foo(); + if (fooResult) { // <- error! :D + return "true"; + } + return "false"; +} +``` + +...the following code would not. + +```ts +async function foo(): Promise { + return false; +} + +async function bar(): Promise { + if (foo()) { // <- no error :( + return "true"; + } + return "false"; +} +``` + +TypeScript 4.4 now flags both. +For more information, [read up on the original change](https://github.com/microsoft/TypeScript/pull/44491). + +## Abstract Properties Do Not Allow Initializers + +The following code is now an error because abstract properties may not have initializers: + +```ts +abstract class C { + abstract prop = 1; + // ~~~~ + // Property 'prop' cannot have an initializer because it is marked abstract. +} +``` + +Instead, you may only specify a type for the property: + +```ts +abstract class C { + abstract prop: number; +} +``` + +# TypeScript 4.3 + +## Union Enums Cannot Be Compared to Arbitrary Numbers + +Certain `enum`s are considered *union `enum`s* when their members are either automatically filled in, or trivially written. +In those cases, an enum can recall each value that it potentially represents. + +In TypeScript 4.3, if a value with a union `enum` type is compared with a numeric literal that it could never be equal to, then the type-checker will isue an error. + +```ts +enum E { + A = 0, + B = 1, +} + +function doSomething(x: E) { + // Error! This condition will always return 'false' since the types 'E' and '-1' have no overlap. + if (x === -1) { + // ... + } +} +``` + +As a workaround, you can re-write an annotation to include the appropriate literal type. + +```ts +enum E { + A = 0, + B = 1, +} + +// Include -1 in the type, if we're really certain that -1 can come through. +function doSomething(x: E | -1) { + if (x === -1) { + // ... + } +} +``` + +You can also use a type-assertion on the value. + +```ts +enum E { + A = 0, + B = 1, +} + +function doSomething(x: E) { + // Use a type asertion on 'x' because we know we're not actually just dealing with values from 'E'. + if ((x as number) === -1) { + // ... + } +} +``` + +Alternatively, you can re-declare your enum to have a non-trivial initializer so that any number is both assignable and comparable to that enum. This may be useful if the intent is for the enum to specify a few well-known values. + +```ts +enum E { + // the leading + on 0 opts TypeScript out of inferring a union enum. + A = +0, + B = 1, +} +``` + +For more details, [see the original change](https://github.com/microsoft/TypeScript/pull/42472) + +# TypeScript 4.2 + +## `noImplicitAny` Errors Apply to Loose `yield` Expressions + +When a `yield` expression is captured, but isn't contextually typed (i.e. TypeScript can't figure out what the type is), TypeScript will now issue an implicit `any` error. + +```ts +function* g1() { + const value = yield 1; // report implicit any error +} + +function* g2() { + yield 1; // result is unused, no error +} + +function* g3() { + const value: string = yield 1; // result is contextually typed by type annotation of `value`, no error. +} + +function* g3(): Generator { + const value = yield 1; // result is contextually typed by return-type annotation of `g3`, no error. +} +``` + +See more details in [the corresponding changes](https://github.com/microsoft/TypeScript/pull/41348). + +## Type Arguments in JavaScript Are Not Parsed as Type Arguments + +Type arguments were already not allowed in JavaScript, but in TypeScript 4.2, the parser will parse them in a more spec-compliant way. +So when writing the following code in a JavaScript file: + +```ts +f(100) +``` + +TypeScript will parse it as the following JavaScript: + +```js +(f < T) > (100) +``` + +This may impact you if you were leveraging TypeScript's API to parse type constructs in JavaScript files, which may have occurred when trying to parse Flow files. + +## The `in` Operator No Longer Allows Primitive Types on the Right Side + +In JavaScript, it is a runtime error to use a non-object type on the right side of the `in` operator. +TypeScript 4.2 ensures this can be caught at design-time. + +```ts +"foo" in 42 +// ~~ +// error! The right-hand side of an 'in' expression must not be a primitive. +``` + +This check is fairly conservative for the most part, so if you have received an error about this, it is likely an issue in the code. + +# TypeScript 4.1 + +## `abstract` Members Can't Be Marked `async` + +Members marked as `abstract` can no longer be marked as `async`. +The fix here is to remove the `async` keyword, since callers are only concerned with the return type. + +## `resolve`'s Parameters Are No Longer Optional in `Promise`s + +When writing code like the following + +```ts +new Promise(resolve => { + doSomethingAsync(() => { + doSomething(); + resolve(); + }) +}) +``` + +You may get an error like the following: + +``` + resolve() + ~~~~~~~~~ +error TS2554: Expected 1 arguments, but got 0. + An argument for 'value' was not provided. +``` + +This is because `resolve` no longer has an optional parameter, so by default, it must now be passed a value. +Often this catches legitimate bugs with using `Promise`s. +The typical fix is to pass it the correct argument, and sometimes to add an explicit type argument. + +```ts +new Promise(resolve => { + // ^^^^^^^^ + doSomethingAsync(value => { + doSomething(); + resolve(value); + // ^^^^^ + }) +}) +``` + +However, sometimes `resolve()` really does need to be called without an argument. +In these cases, we can give `Promise` an explicit `void` generic type argument (i.e. write it out as `Promise`). +This leverages new functionality in TypeScript 4.1 where a potentially-`void` trailing parameter can become optional. + +```ts +new Promise(resolve => { + // ^^^^^^ + doSomethingAsync(() => { + doSomething(); + resolve(); + }) +}) +``` + +TypeScript 4.1 ships with a quick fix to help fix this break. + +## `any` and `unknown` are considered possibly falsy in `&&` expressions + +_**Note:** This change, and the description of the previous behavior, apply only under `--strictNullChecks`._ + +Previously, when an `any` or `unknown` appeared on the left-hand side of an `&&`, it was assumed to be definitely truthy, which made the type of the expression the type of the right-hand side: + +```ts +// Before: + +function before(x: any, y: unknown) { + const definitelyThree = x && 3; // 3 + const definitelyFour = y && 4; // 4 +} + +// Passing any falsy values here demonstrates that `definitelyThree` and `definitelyFour` +// are not, in fact, definitely 3 and 4 at runtime. +before(false, 0); +``` + +In TypeScript 4.1, under `--strictNullChecks`, when `any` or `unknown` appears on the left-hand side of an `&&`, the type of the expression is `any` or `unknown`, respectively: + +```ts +// After: + +function after(x: any, y: unknown) { + const maybeThree = x && 3; // any + const maybeFour = y && 4; // unknown +} +``` + +This change introduces new errors most frequently where TypeScript previously failed to notice that an `unknown` in an `&&` expression may not produce a `boolean`: + +```ts + +function isThing(x: unknown): boolean { + return x && typeof x === "object" && x.hasOwnProperty("thing"); +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// error! +// Type 'unknown' is not assignable to type 'boolean'. +} +``` + +If `x` is a falsy value other than `false`, the function will return it, in conflict with the `boolean` return type annotation. The error can be resolved by replacing the first `x` in the return expression with `!!x`. + +See more details on the [implementing pull request](https://github.com/microsoft/TypeScript/pull/39529). + +## Conditional Spreads Create Optional Properties + +In JavaScript, object spreads (like `{ ...foo }`) don't operate over falsy values. +So in code like `{ ...foo }`, `foo` will be skipped over if it's `null` or `undefined`. + +Many users take advantage of this to spread in properties "conditionally". + +```ts +interface Person { + name: string; + age: number; + location: string; +} + +interface Animal { + name: string; + owner: Person; +} + +function copyOwner(pet?: Animal) { + return { + ...(pet && pet.owner), + otherStuff: 123 + } +} + +// We could also use optional chaining here: + +function copyOwner(pet?: Animal) { + return { + ...(pet?.owner), + otherStuff: 123 + } +} +``` + +Here, if `pet` is defined, the properties of `pet.owner` will be spread in - otherwise, no properties will be spread into the returned object. + +The return type of `copyOwner` was previously a union type based on each spread: + +``` +{ x: number } | { x: number, name: string, age: number, location: string } +``` + +This modeled exactly how the operation would occur: if `pet` was defined, all the properties from `Person` would be present; otherwise, none of them would be defined on the result. +It was an all-or-nothing operation. + +However, we've seen this pattern taken to the extreme, with hundreds of spreads in a single object, each spread potentially adding in hundreds or thousands of properties. +It turns out that for various reasons, this ends up being extremely expensive, and usually for not much benefit. + +In TypeScript 4.1, the returned type instead uses all-optional properties. + +``` +{ + x: number; + name?: string; + age?: number; + location?: string; +} +``` + +This ends up performing better and generally displaying better too. + +For more details, [see the original change](https://github.com/microsoft/TypeScript/pull/40778). + +## Unmatched parameters are no longer related + +TypeScript would previously relate parameters that didn't correspond to each other by relating them to the type `any`. +With [changes in TypeScript 4.1](https://github.com/microsoft/TypeScript/pull/41308), the language now skips this process entirely. +This means that some cases of assignability will now fail, but it also means that some cases of overload resolution can fail as well. +For example, the overloads of `util.promisify` in Node.js may select a different overload in TypeScript 4.1, sometimes causing different errors downstream. + +As a workaround, you may be best using a type assertion to squelch errors. + +# TypeScript 4.0 + +## Properties Overridding Accessors (and vice versa) is an Error + +Previously, it was only an error for properties to override accessors, or accessors to override properties, when using `useDefineForClassFields`; however, TypeScript now always issues an error when declaring a property in a derived class that would override a getter or setter in the base class. + +```ts +class Base { + get foo() { + return 100; + } + set foo() { + // ... + } +} + +class Derived extends Base { + foo = 10; +// ~~~ +// error! +// 'foo' is defined as an accessor in class 'Base', +// but is overridden here in 'Derived' as an instance property. +} +``` + +```ts +class Base { + prop = 10; +} + +class Derived extends Base { + get prop() { + // ~~~~ + // error! + // 'prop' is defined as a property in class 'Base', but is overridden here in 'Derived' as an accessor. + return 100; + } +} +``` + +## Operands for `delete` must be optional. + +When using the `delete` operator in `strictNullChecks`, the operand must now be `any`, `unknown`, `never`, or be optional (in that it contains `undefined` in the type). +Otherwise, use of the `delete` operator is an error. + +```ts +interface Thing { + prop: string; +} + +function f(x: Thing) { + delete x.prop; + // ~~~~~~ + // error! The operand of a 'delete' operator must be optional. +} +``` + +See more details on [the implementing pull request](https://github.com/microsoft/TypeScript/pull/37921). + +See more details on [the implementing pull request](https://github.com/microsoft/TypeScript/pull/37894). + +# TypeScript 3.9 + +## Parsing Differences in Optional Chaining and Non-Null Assertions + +TypeScript recently implemented the optional chaining operator, but we've received user feedback that the behavior of optional chaining (`?.`) with the non-null assertion operator (`!`) is extremely counter-intuitive. + +Specifically, in previous versions, the code + +```ts +foo?.bar!.baz +``` + +was interpreted to be equivalent to the following JavaScript. + +```js +(foo?.bar).baz +``` + +In the above code the parentheses stop the "short-circuiting" behavior of optional chaining, so if `foo` is `undefined`, accessing `baz` will cause a runtime error. + +The Babel team who pointed this behavior out, and most users who provided feedback to us, believe that this behavior is wrong. +We do too! +The thing we heard the most was that the `!` operator should just "disappear" since the intent was to remove `null` and `undefined` from the type of `bar`. + +In other words, most people felt that the original snippet should be interpreted as + +```js +foo?.bar.baz +``` + +which just evaluates to `undefined` when `foo` is `undefined`. + +This is a breaking change, but we believe most code was written with the new interpretation in mind. +Users who want to revert to the old behavior can add explicit parentheses around the left side of the `!` operator. + +```ts +(foo?.bar)!.baz +``` + +For more information, [see the corresponding pull request](https://github.com/microsoft/TypeScript/pull/36539). + +## `}` and `>` are Now Invalid JSX Text Characters + +The JSX Specification forbids the use of the `}` and `>` characters in text positions. +TypeScript and Babel have both decided to enforce this rule to be more comformant. +The new way to insert these characters is to use an HTML escape code (e.g. ` 2 > 1
`) or insert an expression with a string literal (e.g. ` 2 {">"} 1
`). + +In the presence of code like this, you'll get an error message along the lines of + +``` +Unexpected token. Did you mean `{'>'}` or `>`? +Unexpected token. Did you mean `{'}'}` or `}`? +``` + +For example: + +```tsx +let directions = Navigate to: Menu Bar > Tools > Options +// ~ ~ +// Unexpected token. Did you mean `{'>'}` or `>`? +``` + +For more information, see the corresponding [pull request](https://github.com/microsoft/TypeScript/pull/36636). + +## Stricter Checks on Intersections and Optional Properties + +Generally, an intersection type like `A & B` is assignable to `C` if either `A` or `B` is assignable to `C`; however, sometimes that has problems with optional properties. +For example, take the following: + +```ts +interface A { + a: number; // notice this is 'number' +} + +interface B { + b: string; +} + +interface C { + a?: boolean; // notice this is 'boolean' + b: string; +} + +declare let x: A & B; +declare let y: C; + +y = x; +``` + +In previous versions of TypeScript, this was allowed because while `A` was totally incompatible with `C`, `B` *was* compatible with `C`. + +In TypeScript 3.9, so long as every type in an intersection is a concrete object type, the type system will consider all of the properties at once. +As a result, TypeScript will see that the `a` property of `A & B` is incompatible with that of `C`: + +``` +Type 'A & B' is not assignable to type 'C'. + Types of property 'a' are incompatible. + Type 'number' is not assignable to type 'boolean | undefined'. +``` + +For more information on this change, [see the corresponding pull request](https://github.com/microsoft/TypeScript/pull/37195). + +## Intersections Reduced By Discriminant Properties + +There are a few cases where you might end up with types that describe values that just don't exist. +For example + +```ts +declare function smushObjects(x: T, y: U): T & U; + +interface Circle { + kind: "circle"; + radius: number; +} + +interface Square { + kind: "square"; + sideLength: number; +} + +declare let x: Circle; +declare let y: Square; + +let z = smushObjects(x, y); +console.log(z.kind); +``` + +This code is slightly weird because there's really no way to create an intersection of a `Circle` and a `Square` - they have two incompatible `kind` fields. +In previous versions of TypeScript, this code was allowed and the type of `kind` itself was `never` because `"circle" & "square"` described a set of values that could `never` exist. + +In TypeScript 3.9, the type system is more aggressive here - it notices that it's impossible to intersect `Circle` and `Square` because of their `kind` properties. +So instead of collapsing the type of `z.kind` to `never`, it collapses the type of `z` itself (`Circle & Square`) to `never`. +That means the above code now errors with: + +``` +Property 'kind' does not exist on type 'never'. +``` + +Most of the breaks we observed seem to correspond with slightly incorrect type declarations. +For more details, [see the original pull request](https://github.com/microsoft/TypeScript/pull/36696). + +## Getters/Setters are No Longer Enumerable + +In older versions of TypeScript, `get` and `set` accessors in classes were emitted in a way that made them enumerable; however, this wasn't compliant with the ECMAScript specification which states that they must be non-enumerable. +As a result, TypeScript code that targeted ES5 and ES2015 could differ in behavior. + +With [recent changes](https://github.com/microsoft/TypeScript/pull/32264), TypeScript 3.9 now conforms more closely with ECMAScript in this regard. + +## Type Parameters That Extend `any` No Longer Act as `any` + +In previous versions of TypeScript, a type parameter constrained to `any` could be treated as `any`. + +```ts +function foo(arg: T) { + arg.spfjgerijghoied; // no error! +} +``` + +This was an oversight, so TypeScript 3.9 takes a more conservative approach and issues an error on these questionable operations. + +```ts +function foo(arg: T) { + arg.spfjgerijghoied; + // ~~~~~~~~~~~~~~~ + // Property 'spfjgerijghoied' does not exist on type 'T'. +} +``` + +See [the original pull request](https://github.com/microsoft/TypeScript/pull/29571) for more details. + +## `export *` is Always Retained + +In previous TypeScript versions, declarations like `export * from "foo"` would be dropped in our JavaScript output if `foo` didn't export any values. +This sort of emit is problematic because it's type-directed and can't be emulated by Babel. +TypeScript 3.9 will always emit these `export *` declarations. +In practice, we don't expect this to break much existing code, but bundlers may have a harder time tree-shaking the code. + +You can see the specific changes in [the original pull request](https://github.com/microsoft/TypeScript/pull/37124). + +## Exports Now Use Getters for Live Bindings + +When targeting module systems like CommonJS in ES5 and above, TypeScript will use get accessors to emulate live bindings so that changes to a variable in one module are witnessed in any exporting modules. This change is meant to make TypeScript's emit more compliant with ECMAScript modules. + +For more details, see [the PR that applies this change](https://github.com/microsoft/TypeScript/pull/359670). + +## Exports are Hoisted and Initially Assigned + +TypeScript now hoists exported declarations to the top of the file when targeting module systems like CommonJS in ES5 and above. This change is meant to make TypeScript's emit more compliant with ECMAScript modules. For example, code like + +```ts +export * from "mod"; +export const nameFromMod = 0; +``` + +previously had output like + +```ts +__exportStar(exports, require("mod")); +exports.nameFromMod = 0; +``` + +However, because exports now use `get`-accessors, this assignment would throw because `__exportStar` now makes get-accesors which can't be overridden with a simple assignment. Instead, TypeScript 3.9 emits the following: + +```ts +exports.nameFromMod = void 0; +__exportStar(exports, require("mod")); +exports.nameFromMod = 0; +``` + +See [the original pull request](https://github.com/microsoft/TypeScript/pull/37093) for more information. + +# TypeScript 3.8 + +## Stricter Assignability Checks to Unions with Index Signatures + +Previously, excess properties were unchecked when assigning to unions where *any* type had an index signature - even if that excess property could *never* satisfy that index signature. +In TypeScript 3.8, the type-checker is stricter, and only "exempts" properties from excess property checks if that property could plausibly satisfy an index signature. + +```ts +const obj1: { [x: string]: number } | { a: number }; + +obj1 = { a: 5, c: 'abc' } +// ~ +// Error! +// The type '{ [x: string]: number }' no longer exempts 'c' +// from excess property checks on '{ a: number }'. + +let obj2: { [x: string]: number } | { [x: number]: number }; + +obj2 = { a: 'abc' }; +// ~ +// Error! +// The types '{ [x: string]: number }' and '{ [x: number]: number }' no longer exempts 'a' +// from excess property checks against '{ [x: number]: number }', +// and it *is* sort of an excess property because 'a' isn't a numeric property name. +// This one is more subtle. +``` + +## Optional Arguments with no Inferences are Correctly Marked as Implicitly `any` + +In the following code, `param` is now marked with an error under `noImplicitAny`. + +```ts +function foo(f: () => void) { + // ... +} + +foo((param?) => { + // ... +}); +``` + +This is because there is no corresponding parameter for the type of `f` in `foo`. +This seems unlikely to be intentional, but it can be worked around by providing an explicit type for `param`. + +## `object` in JSDoc is No Longer `any` Under `noImplicitAny` + +Historically, TypeScript's support for checking JavaScript has been lax in certain ways in order to provide an approachable experience. + +For example, users often used `Object` in JSDoc to mean, "some object, I dunno what", we've treated it as `any`. + +```js +// @ts-check + +/** + * @param thing {Object} some object, i dunno what + */ +function doSomething(thing) { + let x = thing.x; + let y = thing.y; + thing(); +} +``` + +This is because treating it as TypeScript's `Object` type would end up in code reporting uninteresting errors, since the `Object` type is an extremely vague type with few capabilities other than methods like `toString` and `valueOf`. + +However, TypeScript *does* have a more useful type named `object` (notice that lowercase `o`). +The `object` type is more restrictive than `Object`, in that it rejects all primitive types like `string`, `boolean`, and `number`. +Unfortunately, both `Object` and `object` were treated as `any` in JSDoc. + +Because `object` can come in handy and is used significantly less than `Object` in JSDoc, we've removed the special-case behavior in JavaScript files when using `noImplicitAny` so that in JSDoc, the `object` type really refers to the non-primitive `object` type. + +# TypeScript 3.6 + +## Class Members Named `"constructor"` Are Now Constructors + +As per the ECMAScript specification, class declarations with methods named `constructor` are now constructor functions, regardless of whether they are declared using identifier names, or string names. + +```ts +class C { + "constructor"() { + console.log("I am the constructor now."); + } +} +``` + +A notable exception, and the workaround to this break, is using a computed property whose name evaluates to `"constructor"`. + +```ts +class D { + ["constructor"]() { + console.log("I'm not a constructor - just a plain method!"); + } +} +``` + +## DOM Updates + +Many declarations have been removed or changed within `lib.dom.d.ts`. +This includes (but isn't limited to) the following: + +* The global `window` is no longer defined as type `Window` - instead, it is defined as type `Window & typeof globalThis`. In some cases, it may be better to refer to its type as `typeof window`. +* `GlobalFetch` is gone. Instead, use `WindowOrWorkerGlobalScope` +* Certain non-standard properties on `Navigator` are gone. +* The `experimental-webgl` context is gone. Instead, use `webgl` or `webgl2`. + +## JSDoc Comments No Longer Merge + +In JavaScript files, TypeScript will only consult immediately preceding JSDoc comments to figure out declared types. + +```ts +/** + * @param {string} arg + */ +/** + * oh, hi, were you trying to type something? + */ +function whoWritesFunctionsLikeThis(arg) { + // 'arg' has type 'any' +} +``` + +## Keywords Cannot Contain Escape Sequences + +Previously keywords were not allowed to contain escape sequences. +TypeScript 3.6 disallows them. + +```ts +while (true) { + \u0063ontinue; +// ~~~~~~~~~~~~~ +// error! Keywords cannot contain escape characters. +} +``` + +# TypeScript 3.5 + +## Generic type parameters are implicitly constrained to `unknown` + +In TypeScript 3.5, [generic type parameters without an explicit constraint are now implicitly constrained to `unknown`](https://github.com/Microsoft/TypeScript/pull/30637), whereas previously the implicit constraint of type parameters was the empty object type `{}`. + +In practice, `{}` and `unknown` are pretty similar, but there are a few key differences: + +* `{}` can be indexed with a string (`k["foo"]`), though this is an implicit `any` error under `--noImplicitAny`. +* `{}` is assumed to not be `null` or `undefined`, whereas `unknown` is possibly one of those values. +* `{}` is assignable to `object`, but `unknown` is not. + +On the caller side, this typically means that assignment to `object` will fail, and methods on `Object` like `toString`, `toLocaleString`, `valueOf`, `hasOwnProperty`, `isPrototypeOf`, and `propertyIsEnumerable` will no longer be available. + +```ts +function foo(x: T): [T, string] { + return [x, x.toString()] + // ~~~~~~~~ error! Property 'toString' does not exist on type 'T'. +} +``` + +As a workaround, you can add an explicit constraint of `{}` to a type parameter to get the old behavior. + +```ts +// vvvvvvvvvv +function foo(x: T): [T, string] { + return [x, x.toString()] +} +``` + +From the caller side, failed inferences for generic type arguments will result in `unknown` instead of `{}`. + +```ts +function parse(x: string): T { + return JSON.parse(x); +} + +// k has type 'unknown' - previously, it was '{}'. +const k = parse("..."); +``` + +As a workaround, you can provide an explicit type argument: + +```ts +// 'k' now has type '{}' +const k = parse<{}>("..."); +``` + +### `{ [k: string]: unknown }` is no longer a wildcard assignment target + +The index signature `{ [s: string]: any }` in TypeScript behaves specially: it's a valid assignment target for any object type. +This is a special rule, since types with index signatures don't normally produce this behavior. + +Since its introduction, the type `unknown` in an index signature behaved the same way: + +```ts +let dict: { [s: string]: unknown }; +// Was OK +dict = () => {}; +``` + +In general this rule makes sense; the implied constraint of "all its properties are some subtype of `unknown`" is trivially true of any object type. +However, in TypeScript 3.5, this special rule is removed for `{ [s: string]: unknown }`. + +This was a necessary change because of the change from `{}` to `unknown` when generic inference has no candidates. +Consider this code: + +```ts +declare function someFunc(): void; +declare function fn(arg: { [k: string]: T }): void; +fn(someFunc); +``` + +In TypeScript 3.4, the following sequence occurred: + +* No candidates were found for `T` +* `T` is selected to be `{}` +* `someFunc` isn't assignable to `arg` because there are no special rules allowing arbitrary assignment to `{ [k: string]: {} }` +* The call is correctly rejected + +Due to changes around unconstrained type parameters falling back to `unknown` (see above), `arg` would have had the type `{ [k: string]: unknown }`, which anything is assignable to, so the call would have incorrectly been allowed. +That's why TypeScript 3.5 removes the specialized assignability rule to permit assignment to `{ [k: string]: unknown }`. + +Note that fresh object literals are still exempt from this check. + +```ts +const obj = { m: 10 }; +// OK +const dict: { [s: string]: unknown } = obj; +``` + +Depending on the intended behavior of `{ [s: string]: unknown }`, several alternatives are available: + +* `{ [s: string]: any }` +* `{ [s: string]: {} }` +* `object` +* `unknown` +* `any` + +We recommend sketching out your desired use cases and seeing which one is the best option for your particular use case. + +## Improved excess property checks in union types + +### Background + +TypeScript has a feature called *excess property checking* in object literals. +This feature is meant to detect typos for when a type isn't expecting a specific property. + +```ts +type Style = { + alignment: string, + color?: string +}; + +const s: Style = { + alignment: "center", + colour: "grey" +// ^^^^^^ error! +}; +``` + +### Rationale and Change + +In TypeScript 3.4 and earlier, certain excess properties were allowed in situations where they really shouldn't have been. + +Consider this code: +```ts +type Point = { + x: number; + y: number; +}; + +type Label = { + name: string; +}; + +const pl: Point | Label = { + x: 0, + y: 0, + name: true // <- danger! +}; +``` + +Excess property checking was previously only capable of detecting properties which weren't present in *any* member of a target union type. + +In TypeScript 3.5, these excess properties are now correctly detected, and the sample above correctly issues an error. + +Note that it's still legal to be assignable to multiple parts of a union: + +```ts +const pl: Point | Label = { + x: 0, + y: 0, + name: "origin" // OK +}; +``` + +### Workarounds + +We have not witnessed examples where this checking hasn't caught legitimate issues, but in a pinch, any of the workarounds to disable excess property checking will apply: + +* Add a type assertion onto the object (e.g. `{ myProp: SomeType } as ExpectedType`) +* Add an index signature to the expected type to signal that unspecified properties are expected (e.g. `interface ExpectedType { myProp: SomeType; [prop: string]: unknown }`) + +## Fixes to Unsound Writes to Indexed Access Types + +### Background + +TypeScript allows you to represent the abstract operation of accessing a property of an object via the name of that property: + +```ts +type A = { + s: string; + n: number; +}; + +function read(arg: A, key: K): A[K] { + return arg[key]; +} + +const a: A = { s: "", n: 0 }; +const x = read(a, "s"); // x: string +``` + +While commonly used for reading values from an object, you can also use this for writes: + +```ts +function write(arg: A, key: K, value: A[K]): void { + arg[key] = value; +} +``` + +### Change and Rationale + +In TypeScript 3.4, the logic used to validate a *write* was much too permissive: + +```ts +function write(arg: A, key: K, value: A[K]): void { + // ??? + arg[key] = "hello, world"; +} +// Breaks the object by putting a string where a number should be +write(a, "n"); +``` + +In TypeScript 3.5, this logic is fixed and the above sample correctly issues an error. + +### Workarounds + +Most instances of this error represent potential errors in the relevant code. + +One example we found looked like this: +```ts +type T = { + a: string, + x: number, + y: number +}; +function write(obj: T, k: K) { + // Trouble waiting + obj[k] = 1; +} +const someObj: T = { a: "", x: 0, y: 0 }; +// Note: write(someObj, "a") never occurs, so the code is technically bug-free (?) +write(someObj, "x"); +write(someObj, "y"); +``` + +This function can be fixed to only accept keys which map to numeric properties: + +```ts +// Generic helper type that produces the keys of an object +// type which map to properties of some other specific type +type KeysOfType = K extends K ? TObj[K] extends TProp ? K : never : never; + +function write(obj: SomeObj, k: KeysOfType) { + // OK + obj[k] = 1; +} + +const someObj: SomeObj = { a: "", x: 0, y: 0 }; +write(someObj, "x"); +write(someObj, "y"); +// Correctly an error +write(someObj, "a"); +``` + +## `lib.d.ts` includes the `Omit` helper type + +TypeScript 3.5 includes a new `Omit` helper type. +As a result, any global declarations of `Omit` included in your project will result in the following error message: + +```ts +Duplicate identifier 'Omit'. +``` + +Two workarounds may be used here: + +1. Delete the duplicate declaration and use the one provided in `lib.d.ts`. +2. Export the existing declaration from a module file or a namespace to avoid a global collision. Existing usages can use an `import` or explicit reference to your project's old `Omit` type. + +## `Object.keys` rejects primitives in ES5 + +### Background + +In ECMAScript 5 environments, `Object.keys` throws an exception if passed any non-`object` argument: + +```ts +// Throws if run in an ES5 runtime +Object.keys(10); +``` + +In ECMAScript 2015, `Object.keys` returns `[]` if its argument is a primitive: + +```ts +// [] in ES6 runtime +Object.keys(10); +``` + +### Rationale and Change + +This is a potential source of error that wasn't previously identified. + +In TypeScript 3.5, if `target` (or equivalently `lib`) is `ES5`, calls to `Object.keys` must pass a valid `object`. + +### Workarounds + +In general, errors here represent possible exceptions in your application and should be treated as such. +If you happen to know through other means that a value is an `object`, a type assertion is appropriate: + +```ts +function fn(arg: object | number, isArgActuallyObject: boolean) { + if (isArgActuallyObject) { + const k = Object.keys(arg as object); + } +} +``` + +Note that this change interacts with the change in generic inference from `{}` to `unknown`, because `{}` is a valid `object` whereas `unknown` isn't: + +```ts +declare function fn(): T; + +// Was OK in TypeScript 3.4, errors in 3.5 under --target ES5 +Object.keys(fn()); +``` + +# TypeScript 3.4 + +## Top-level `this` is now typed + +The type of top-level `this` is now typed as `typeof globalThis` instead of `any`. +As a consequence, you may receive errors for accessing unknown values on `this` under `noImplicitAny`. + +```ts +// previously okay in noImplicitAny, now an error +this.whargarbl = 10; +``` + +Note that code compiled under `noImplicitThis` will not experience any changes here. + +## Propagated generic type arguments + +In certain cases, TypeScript 3.4's improved inference might produce functions that are generic, rather than ones that take and return their constraints (usually `{}`). + +```ts +declare function compose(f: (arg: T) => U, g: (arg: U) => V): (arg: T) => V; + +function list(x: T) { return [x]; } +function box(value: T) { return { value }; } + +let f = compose(list, box); +let x = f(100) + +// In TypeScript 3.4, 'x.value' has the type +// +// number[] +// +// but it previously had the type +// +// {}[] +// +// So it's now an error to push in a string. +x.value.push("hello"); +``` + +An explicit type annotation on `x` can get rid of the error. + +### Contextual return types flow in as contextual argument types + +TypeScript now uses types that flow into function calls (like `then` in the below example) to contextually type function arguments (like the arrow function in the below example). + +```ts +function isEven(prom: Promise): Promise<{ success: boolean }> { + return prom.then((x) => { + return x % 2 === 0 ? + { success: true } : + Promise.resolve({ success: false }); + }); +} +``` + +This is generally an improvement, but in the above example it causes `true` and `false` to acquire literal types which is undesirable. + +``` +Argument of type '(x: number) => Promise<{ success: false; }> | { success: true; }' is not assignable to parameter of type '(value: number) => { success: false; } | PromiseLike<{ success: false; }>'. + Type 'Promise<{ success: false; }> | { success: true; }' is not assignable to type '{ success: false; } | PromiseLike<{ success: false; }>'. + Type '{ success: true; }' is not assignable to type '{ success: false; } | PromiseLike<{ success: false; }>'. + Type '{ success: true; }' is not assignable to type '{ success: false; }'. + Types of property 'success' are incompatible. + +``` + +The appropriate workaround is to add type arguments to the appropriate call - the `then` method call in this example. + +```ts +function isEven(prom: Promise): Promise<{ success: boolean }> { + // vvvvvvvvvvvvvvvvvv + return prom.then<{success: boolean}>((x) => { + return x % 2 === 0 ? + { success: true } : + Promise.resolve({ success: false }); + }); +} +``` + +### Consistent inference priorities outside of `strictFunctionTypes` + +In TypeScript 3.3 with `--strictFunctionTypes` off, generic types declared with `interface` were assumed to always be covariant with respect to their type parameter. +For function types, this behavior was generally not observable. +However, for generic `interface` types that used their type parameters with `keyof` positions - a contravariant use - these types behaved incorrectly. + +In TypeScript 3.4, variance of types declared with `interface` is now correctly measured in all cases. +This causes an observable breaking change for interfaces that used a type parameter only in `keyof` (including places like `Record` which is an alias for a type involving `keyof K`). The example above is one such possible break. + +```ts +interface HasX { x: any } +interface HasY { y: any } + +declare const source: HasX | HasY; +declare const properties: KeyContainer; + +interface KeyContainer { + key: keyof T; +} + +function readKey(source: T, prop: KeyContainer) { + console.log(source[prop.key]) +} + +// This call should have been rejected, because we might +// incorrectly be reading 'x' from 'HasY'. It now appropriately errors. +readKey(source, properties); +``` + +This error is likely indicative of an issue with the original code. + +# TypeScript 3.2 + +## `lib.d.ts` updates + +### `wheelDelta` and friends have been removed. + +`wheelDeltaX`, `wheelDelta`, and `wheelDeltaZ` have all been removed as they is a deprecated properties on `WheelEvent`s. + +**Solution**: Use `deltaX`, `deltaY`, and `deltaZ` instead. + +### More specific types + +Certain parameters no longer accept `null`, or now accept more specific types as per the corresponding specifications that describe the DOM. + +# TypeScript 3.1 + +## Some vendor-specific types are removed from `lib.d.ts` + +TypeScript's built-in `.d.ts` library (`lib.d.ts` and family) is now partially generated from Web IDL files from the DOM specification. As a result some vendor-specific types have been removed. + +
Click here to read the full list of removed types:

+ +* `CanvasRenderingContext2D.mozImageSmoothingEnabled` +* `CanvasRenderingContext2D.msFillRule` +* `CanvasRenderingContext2D.oImageSmoothingEnabled` +* `CanvasRenderingContext2D.webkitImageSmoothingEnabled` +* `Document.caretRangeFromPoint` +* `Document.createExpression` +* `Document.createNSResolver` +* `Document.execCommandShowHelp` +* `Document.exitFullscreen` +* `Document.exitPointerLock` +* `Document.focus` +* `Document.fullscreenElement` +* `Document.fullscreenEnabled` +* `Document.getSelection` +* `Document.msCapsLockWarningOff` +* `Document.msCSSOMElementFloatMetrics` +* `Document.msElementsFromRect` +* `Document.msElementsFromPoint` +* `Document.onvisibilitychange` +* `Document.onwebkitfullscreenchange` +* `Document.onwebkitfullscreenerror` +* `Document.pointerLockElement` +* `Document.queryCommandIndeterm` +* `Document.URLUnencoded` +* `Document.webkitCurrentFullScreenElement` +* `Document.webkitFullscreenElement` +* `Document.webkitFullscreenEnabled` +* `Document.webkitIsFullScreen` +* `Document.xmlEncoding` +* `Document.xmlStandalone` +* `Document.xmlVersion` +* `DocumentType.entities` +* `DocumentType.internalSubset` +* `DocumentType.notations` +* `DOML2DeprecatedSizeProperty` +* `Element.msContentZoomFactor` +* `Element.msGetUntransformedBounds` +* `Element.msMatchesSelector` +* `Element.msRegionOverflow` +* `Element.msReleasePointerCapture` +* `Element.msSetPointerCapture` +* `Element.msZoomTo` +* `Element.onwebkitfullscreenchange` +* `Element.onwebkitfullscreenerror` +* `Element.webkitRequestFullScreen` +* `Element.webkitRequestFullscreen` +* `ElementCSSInlineStyle` +* `ExtendableEventInit` +* `ExtendableMessageEventInit` +* `FetchEventInit` +* `GenerateAssertionCallback` +* `HTMLAnchorElement.Methods` +* `HTMLAnchorElement.mimeType` +* `HTMLAnchorElement.nameProp` +* `HTMLAnchorElement.protocolLong` +* `HTMLAnchorElement.urn` +* `HTMLAreasCollection` +* `HTMLHeadElement.profile` +* `HTMLImageElement.msGetAsCastingSource` +* `HTMLImageElement.msGetAsCastingSource` +* `HTMLImageElement.msKeySystem` +* `HTMLImageElement.msPlayToDisabled` +* `HTMLImageElement.msPlayToDisabled` +* `HTMLImageElement.msPlayToPreferredSourceUri` +* `HTMLImageElement.msPlayToPreferredSourceUri` +* `HTMLImageElement.msPlayToPrimary` +* `HTMLImageElement.msPlayToPrimary` +* `HTMLImageElement.msPlayToSource` +* `HTMLImageElement.msPlayToSource` +* `HTMLImageElement.x` +* `HTMLImageElement.y` +* `HTMLInputElement.webkitdirectory` +* `HTMLLinkElement.import` +* `HTMLMetaElement.charset` +* `HTMLMetaElement.url` +* `HTMLSourceElement.msKeySystem` +* `HTMLStyleElement.disabled` +* `HTMLSummaryElement` +* `MediaQueryListListener` +* `MSAccountInfo` +* `MSAudioLocalClientEvent` +* `MSAudioLocalClientEvent` +* `MSAudioRecvPayload` +* `MSAudioRecvSignal` +* `MSAudioSendPayload` +* `MSAudioSendSignal` +* `MSConnectivity` +* `MSCredentialFilter` +* `MSCredentialParameters` +* `MSCredentials` +* `MSCredentialSpec` +* `MSDCCEvent` +* `MSDCCEventInit` +* `MSDelay` +* `MSDescription` +* `MSDSHEvent` +* `MSDSHEventInit` +* `MSFIDOCredentialParameters` +* `MSIceAddrType` +* `MSIceType` +* `MSIceWarningFlags` +* `MSInboundPayload` +* `MSIPAddressInfo` +* `MSJitter` +* `MSLocalClientEvent` +* `MSLocalClientEventBase` +* `MSNetwork` +* `MSNetworkConnectivityInfo` +* `MSNetworkInterfaceType` +* `MSOutboundNetwork` +* `MSOutboundPayload` +* `MSPacketLoss` +* `MSPayloadBase` +* `MSPortRange` +* `MSRelayAddress` +* `MSSignatureParameters` +* `MSStatsType` +* `MSStreamReader` +* `MSTransportDiagnosticsStats` +* `MSUtilization` +* `MSVideoPayload` +* `MSVideoRecvPayload` +* `MSVideoResolutionDistribution` +* `MSVideoSendPayload` +* `NotificationEventInit` +* `PushEventInit` +* `PushSubscriptionChangeInit` +* `RTCIdentityAssertionResult` +* `RTCIdentityProvider` +* `RTCIdentityProviderDetails` +* `RTCIdentityValidationResult` +* `Screen.deviceXDPI` +* `Screen.logicalXDPI` +* `SVGElement.xmlbase` +* `SVGGraphicsElement.farthestViewportElement` +* `SVGGraphicsElement.getTransformToElement` +* `SVGGraphicsElement.nearestViewportElement` +* `SVGStylable` +* `SVGTests.hasExtension` +* `SVGTests.requiredFeatures` +* `SyncEventInit` +* `ValidateAssertionCallback` +* `WebKitDirectoryEntry` +* `WebKitDirectoryReader` +* `WebKitEntriesCallback` +* `WebKitEntry` +* `WebKitErrorCallback` +* `WebKitFileCallback` +* `WebKitFileEntry` +* `WebKitFileSystem` +* `Window.clearImmediate` +* `Window.msSetImmediate` +* `Window.setImmediate` +

+ +### Recommendations: + +If your run-time guarantees that some of these names are available at run-time (e.g. for an IE-only app), add the declarations locally in your project, e.g.: + +For `Element.msMatchesSelector`, add the following to a local `dom.ie.d.ts` + +```ts +interface Element { + msMatchesSelector(selectors: string): boolean; +} +``` + +Similarly, to add `clearImmediate` and `setImmediate`, you can add a declaration for `Window` in your local `dom.ie.d.ts`: + +```ts +interface Window { + clearImmediate(handle: number): void; + setImmediate(handler: (...args: any[]) => void): number; + setImmediate(handler: any, ...args: any[]): number; +} +``` + +## Narrowing functions now intersects `{}`, `Object`, and unconstrained generic type parameters. + +The following code will now complain about `x` no longer being callable: + +```ts +function foo(x: T | (() => string)) { + if (typeof x === "function") { + x(); +// ~~~ +// Cannot invoke an expression whose type lacks a call signature. Type '(() => string) | (T & Function)' has no compatible call signatures. + } +} +``` + +This is because, unlike previously where `T` would be narrowed away, it is now *expanded* into `T & Function`. However, because this type has no call signatures declared, the type system won't find any common call signature between `T & Function` and `() => string`. + +Instead, consider using a more specific type than `{}` or `Object`, and consider adding additional constraints to what you expect `T` might be. + +# TypeScript 3.0 + +## The `unknown` keyword is reserved + +`unknown` is now a reserved type name, as it is now a built-in type. Depending on your intended use of `unknown`, you may want to remove the declaration entirely (favoring the newly introduced `unknown` type), or rename it to something else. + +## Intersecting with `null`/`undefined` reduces to `null`/`undefined` outside of `strictNullChecks` + +In the following example, `A` has the type `null` and `B` has the type `undefined` when `strictNullChecks` is turned off: + +```ts +type A = { a: number } & null; // null +type B = { a: number } & undefined; // undefined +``` + +This is because TypeScript 3.0 is better at reducing subtypes and supertypes in intersection and union types respectively; however, because `null` and `undefined` are both considered subtypes of every other type when `strictNullChecks` is off, an intersection with some object type and either will always reduce to `null` or `undefined`. + +### Recommendation + +If you were relying on `null` and `undefined` to be ["identity" elements](https://en.wikipedia.org/wiki/Identity_element) under intersections, you should look for a way to use `unknown` instead of `null` or `undefined` wherever they appeared + +# TypeScript 2.9 + +## `keyof` now includes `string`, `number` and `symbol` keys + +TypeScript 2.9 generalizes index types to include `number` and `symbol` named properties. Previously, the `keyof` operator and mapped types only supported `string` named properties. + +```ts +function useKey(o: T, k: K) { + var name: string = k; // Error: keyof T is not assignable to string +} +``` + +### Recommendations: +* If your functions are only able to handle string named property keys, use `Extract` in the declaration: + + ```ts + function useKey>(o: T, k: K) { + var name: string = k; // OK + } + ``` + +* If your functions are open to handling all property keys, then the changes should be done down-stream: + + ```ts + function useKey(o: T, k: K) { + var name: string | number | symbol = k; + } + ``` + +* Otherwise use `--keyofStringsOnly` compiler option to disable the new behavior. + +## Trailing commas not allowed on rest parameters + +The following code is a compiler error as of [#22262](https://github.com/Microsoft/TypeScript/pull/22262): +```ts +function f( + a: number, + ...b: number[], // Illegal trailing comma +) {} +``` +Trailing commas on rest parameters are not valid JavaScript, and the syntax is now an error in TypeScript too. + +## In `strictNullChecks`, an unconstrained type parameter is no longer assignable to `object` + +The following code is a compiler error under `strictNullChecks` as of [#24013](https://github.com/Microsoft/TypeScript/issues/24013): +```ts +function f(x: T) { + const y: object | null | undefined = x; +} +``` + +It may be fulfilled with any type (eg, `string` or `number`), so it was incorrect to allow. If you encounter this issue, either constrain your type parameter to `object` to only allow object types for it, or compare against `{}` instead of `object` (if the intent was to allow any type). + + +# TypeScript 2.8 + +## Unused type parameters are checked under `--noUnusedParameters` + +As per [#20568](https://github.com/Microsoft/TypeScript/issues/20568), unused type parameters were previously reported under `--noUnusedLocals`, but are now instead reported under `--noUnusedParameters`. + +## Some MS-specific types are removed from `lib.d.ts` + +Some MS-specific types are removed from the DOM definition to better align with the standard. Types removed include: +* `MSApp` +* `MSAppAsyncOperation` +* `MSAppAsyncOperationEventMap` +* `MSBaseReader` +* `MSBaseReaderEventMap` +* `MSExecAtPriorityFunctionCallback` +* `MSHTMLWebViewElement` +* `MSManipulationEvent` +* `MSRangeCollection` +* `MSSiteModeEvent` +* `MSUnsafeFunctionCallback` +* `MSWebViewAsyncOperation` +* `MSWebViewAsyncOperationEventMap` +* `MSWebViewSettings` + +## `HTMLObjectElement` no longer has an `alt` attribute + +As per [#21386](https://github.com/Microsoft/TypeScript/issues/21386), the DOM libraries have been updated to reflect the WHATWG standard. + +If you need to continue using the `alt` attribute, consider reopening `HTMLObjectElement` via interface merging in the global scope: + +```ts +// Must be in a global .ts file or a 'declare global' block. +interface HTMLObjectElement { + alt: string; +} +``` + +# TypeScript 2.7 + +For a full list of breaking changes see the [breaking change issues](https://github.com/Microsoft/TypeScript/issues?q=is%3Aissue+milestone%3A%22TypeScript+2.7%22+label%3A%22Breaking+Change%22+is%3Aclosed). + +## Tuples now have a fixed length property + +The following code used to have no compile errors: + +```ts +var pair: [number, number] = [1, 2]; +var triple: [number, number, number] = [1, 2, 3]; +pair = triple; +``` + +However, this *was* an error: + +```ts +triple = pair; +``` + +Now both assignments are an error. +This is because tuples now have a length property whose type is their length. +So `pair.length: 2`, but `triple.length: 3`. + +Note that certain non-tuple patterns were allowed previously, but are no longer allowed: + +```ts +const struct: [string, number] = ['key']; +for (const n of numbers) { + struct.push(n); +} +``` + +The best fix for this is to make your own type that extends Array: + +```ts +interface Struct extends Array { + '0': string; + '1'?: number; +} +const struct: Struct = ['key']; +for (const n of numbers) { + struct.push(n); +} +``` + +## Under `allowSyntheticDefaultImports`, types for default imports are synthesized less often for TS and JS files + +In the past, we'd synthesize a default import in the typesystem for a TS or JS file written like so: +```ts +export const foo = 12; +``` +meaning the module would have the type `{foo: number, default: {foo: number}}`. +This would be wrong, because the file would be emitted with an `__esModule` marker, so no popular module loader would ever create a synthetic default for it when loading the file, and the `default` member that the typesystem inferred was there would never exist at runtime. Now that we emulate this synthetic default behavior in our emit under the `ESModuleInterop` flag, we've tightened the typechecker behavior to match the shape you'd expect to see at runtime. Without the intervention of other tools at runtime, this change should only point out mistakenly incorrect import default usages which should be changed to namespace imports. + +## Stricter checking for indexed access generic type constraints + +Previously the constraint of an indexed access type was only computed if the type had an index signature, otherwise it was `any`. That allowed invalid assignments to go unchecked. In TS 2.7.1, the compiler is a bit smarter here, and will compute the constraint to be the union of all possible properties here. + +```ts +interface O { + foo?: string; +} + +function fails(o: O, k: K) { + var s: string = o[k]; // Previously allowed, now an error + // string | undefined is not assignable to a string +} + +``` +## `in` expressions are treated as type guards + +For a `n in x` expression, where `n` is a string literal or string literal type and `x` is a union type, the "true" branch narrows to types which have an optional or required property `n`, and the "false" branch narrows to types which have an optional or missing property `n`. This may result in cases where the type of a variable is narrowed to `never` in the false branch if the type is declared to always have the the property `n`. + +```ts +var x: { foo: number }; + +if ("foo" in x) { + x; // { foo: number } +} +else { + x; // never +} +``` + +## Structurally-equivalent classes are not reduced in conditional operator + +Previously classes that were structurally equivalent were reduced to their best common type in a conditional or `||` operator. Now these classes are maintained in a union type to allow for more accurate checking for `instanceof` operators. + +```ts +class Animal { + +} + +class Dog { + park() { } +} + +var a = Math.random() ? new Animal() : new Dog(); +// typeof a now Animal | Dog, previously Animal +``` + +## `CustomEvent` is now a generic type + +`CustomEvent` now has a type parameter for the type of the `details` property. If you are extending from it, you will need to specify an additional type parameter. + +```ts +class MyCustomEvent extends CustomEvent { +} +``` +should become + +```ts +class MyCustomEvent extends CustomEvent { +} +``` + +# TypeScript 2.6 + +For full list of breaking changes see the [breaking change issues](https://github.com/Microsoft/TypeScript/issues?q=is%3Aissue+milestone%3A%22TypeScript+2.6%22+label%3A%22Breaking+Change%22+is%3Aclosed). + +## Write-only references are unused + +The following code used to have no compile errors: + +```ts +function f(n: number) { + n = 0; +} + +class C { + private m: number; + constructor() { + this.m = 0; + } +} +``` + +Now when the `--noUnusedLocals` and `--noUnusedParameters` [compiler options](https://www.typescriptlang.org/docs/handbook/compiler-options.html) are enabled, both `n` and `m` will be marked as unused, because their values are never *read*. Previously TypeScript would only check whether their values were *referenced*. + +Also recursive functions that are only called within their own bodies are considered unused. + +```ts +function f() { + f(); // Error: 'f' is declared but its value is never read +} +``` + +## Arbitrary expressions are forbidden in export assignments in ambient contexts + +Previously, constructs like +```ts +declare module "foo" { + export default "some" + "string"; +} +``` +was not flagged as an error in ambient contexts. Expressions are generally forbidden in declaration files and ambient modules, as things like `typeof` have unclear intent, so this was inconsistent with our handling of executable code elsewhere in these contexts. Now, anything which is not an identifier or qualified name is flagged as an error. The correct way to make a DTS for a module with the value shape described above would be like so: +```ts +declare module "foo" { + const _default: string; + export default _default; +} +``` +The compiler already generated definitions like this, so this should only be an issue for definitions which were written by hand. + +# TypeScript 2.4 + +For full list of breaking changes see the [breaking change issues](https://github.com/Microsoft/TypeScript/issues?q=is%3Aissue+milestone%3A%22TypeScript+2.4%22+label%3A%22Breaking+Change%22+is%3Aclosed). + +## Weak Type Detection + +TypeScript 2.4 introduces the concept of "weak types". +Any type that contains nothing but a set of all-optional properties is considered to be *weak*. +For example, this `Options` type is a weak type: + +```ts +interface Options { + data?: string, + timeout?: number, + maxRetries?: number, +} +``` + +In TypeScript 2.4, it's now an error to assign anything to a weak type when there's no overlap in properties. +For example: + +```ts +function sendMessage(options: Options) { + // ... +} + +const opts = { + payload: "hello world!", + retryOnFail: true, +} + +// Error! +sendMessage(opts); +// No overlap between the type of 'opts' and 'Options' itself. +// Maybe we meant to use 'data'/'maxRetries' instead of 'payload'/'retryOnFail'. +``` + +**Recommendation** + +1. Declare the properties if they really do exist. +2. Add an index signature to the weak type (i.e. `[propName: string]: {}`). +3. Use a type assertion (i.e. `opts as Options`). + + +## Return types as inference targets + +TypeScript can now make inferences from contextual types to the return type of a call. +This means that some code may now appropriately error. +As an example of a new errors you might spot as a result: + +```ts +let x: Promise = new Promise(resolve => { + resolve(10); + // ~~ Error! Type 'number' is not assignable to 'string'. +}); +``` + +## Stricter variance in callback parameters + +TypeScript's checking of callback parameters is now covariant with respect to immediate signature checks. +Previously it was bivariant, which could sometimes let incorrect types through. +Basically, this means that callback parameters and classes that +contain callbacks are checked more carefully, so Typescript will +require stricter types in this release. +This is particularly true of Promises and Observables due to the way in which their APIs are specified. + +### Promises + +Here is an example of improved Promise checking: + +```ts +let p = new Promise((c, e) => { c(12) }); +let u: Promise = p; + ~ +Type 'Promise<{}>' is not assignable to 'Promise' +``` + +The reason this occurs is that TypeScript is not able to infer the type argument `T` when you call `new Promise`. +As a result, it just infers `Promise<{}>`. +Unfortunately, this allows you to write `c(12)` and `c('foo')`, even though the declaration of `p` explicitly says that it must be `Promise`. + +Under the new rules, `Promise<{}>` is not assignable to +`Promise` because it breaks the callbacks to Promise. +TypeScript still isn't able to infer the type argument, so to fix this you have to provide the type argument yourself: + +```ts +let p: Promise = new Promise((c, e) => { c(12) }); +// ^^^^^^^^ explicit type arguments here +``` + +This requirement helps find errors in the body of the promise code. +Now if you mistakenly call `c('foo')`, you get the following error: + +```ts +let p: Promise = new Promise((c, e) => { c('foo') }); +// ~~~~~ +// Argument of type '"foo"' is not assignable to 'number' +``` + +### (Nested) Callbacks + +Other callbacks are affected by the improved callback checking as +well, primarily nested callbacks. Here's an example with a function +that takes a callback, which takes a nested callback. The nested +callback is now checked co-variantly. + +```ts +declare function f( + callback: (nested: (error: number, result: any) => void, index: number) => void +): void; + +f((nested: (error: number) => void) => { log(error) }); + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +'(error: number) => void' is not assignable to (error: number, result: any) => void' +``` + +The fix is easy in this case. Just add the missing parameter to the +nested callback: + +```ts +f((nested: (error: number, result: any) => void) => { }); +``` + +## Stricter checking for generic functions + +TypeScript now tries to unify type parameters when comparing two single-signature types. +As a result, you'll get stricter checks when relating two generic signatures, and may catch some bugs. + +```ts +type A = (x: T, y: U) => [T, U]; +type B = (x: S, y: S) => [S, S]; + +function f(a: A, b: B) { + a = b; // Error + b = a; // Ok +} +``` + +**Recommendation** + +Either correct the definition or use `--noStrictGenericChecks`. + +## Type parameter inference from contextual types + +Prior to TypeScript 2.4, in the following example + +```ts +let f: (x: T) => T = y => y; +``` + +`y` would have the type `any`. +This meant the program would type-check, but you could technically do anything with `y`, such as the following: + +```ts +let f: (x: T) => T = y => y() + y.foo.bar; +``` + +**Recommendation:** Appropriately re-evaluate whether your generics have the correct constraint, or are even necessary. As a last resort, annotate your parameters with the `any` type. + +# TypeScript 2.3 + +For full list of breaking changes see the [breaking change issues](https://github.com/Microsoft/TypeScript/issues?q=is%3Aissue+milestone%3A%22TypeScript+2.3%22+label%3A%22Breaking+Change%22+is%3Aclosed). + +## Empty generic parameter lists are flagged as error + +**Example** + +```ts +class X<> {} // Error: Type parameter list cannot be empty. +function f<>() {} // Error: Type parameter list cannot be empty. +const x: X<> = new X<>(); // Error: Type parameter list cannot be empty. +``` + + +# TypeScript 2.2 + +For full list of breaking changes see the [breaking change issues](https://github.com/Microsoft/TypeScript/issues?q=is%3Aissue+milestone%3A%22TypeScript+2.2%22+label%3A%22Breaking+Change%22+is%3Aclosed). + +## Changes to DOM API's in the standard library + +* Standard library now has declarations for `Window.fetch`; dependencies to `@types\whatwg-fetch` will cause conflicting declaration errors and will need to be removed. + +* Standard library now has declarations for `ServiceWorker`; dependencies on `@types\service_worker_api` will cause conflicting declaration errors and will need to be removed. + +# TypeScript 2.1 + +For full list of breaking changes see the [breaking change issues](https://github.com/Microsoft/TypeScript/issues?q=is%3Aissue+milestone%3A%22TypeScript+2.1%22+label%3A%22Breaking+Change%22+is%3Aclosed). + +## Generated constructor code substitutes the return value of `super(...)` calls as `this` + +In ES2015, constructors which return an object implicitly substitute the value of `this` for any callers of `super(...)`. +As a result, it is necessary to capture any potential return value of `super(...)` and replace it with `this`. + +**Example** + +A class `C` as: + +```ts +class C extends B { + public a: number; + constructor() { + super(); + this.a = 0; + } +} +``` + +Will generate code as: + +```js +var C = (function (_super) { + __extends(C, _super); + function C() { + var _this = _super.call(this) || this; + _this.a = 0; + return _this; + } + return C; +}(B)); +``` + +Notice: + * `_super.call(this)` is captured into a local variable `_this` + * All uses of `this` in the constructor body has been replaced by the result of the `super` call (i.e. `_this`) + * Each constructor now returns explicitly its `this`, to enable for correct inheritance + +It is worth noting that the use of `this` before `super(...)` is already an error as of [TypeScript 1.8](#disallow-this-accessing-before-super-call) + +## Extending built-ins like `Error`, `Array`, and `Map` may no longer work + +As part of substituting the value of `this` with the value returned by a `super(...)` call, subclassing `Error`, `Array`, and others may no longer work as expected. +This is due to the fact that constructor functions for `Error`, `Array`, and the like use ECMAScript 6's `new.target` to adjust the prototype chain; +however, there is no way to ensure a value for `new.target` when invoking a constructor in ECMAScript 5. +Other downlevel compilers generally have the same limitation by default. + +**Example** + +For a subclass like the following: + +```ts +class FooError extends Error { + constructor(m: string) { + super(m); + } + sayHello() { + return "hello " + this.message; + } +} +``` + +you may find that: + +* methods may be `undefined` on objects returned by constructing these subclasses, so calling `sayHello` will result in an error. +* `instanceof` will be broken between instances of the subclass and their instances, so `(new FooError()) instanceof FooError` will return `false`. + +**Recommendation** + +As a recommendation, you can manually adjust the prototype immediately after any `super(...)` calls. + +```ts +class FooError extends Error { + constructor(m: string) { + super(m); + + // Set the prototype explicitly. + Object.setPrototypeOf(this, FooError.prototype); + } + + sayHello() { + return "hello " + this.message; + } +} +``` + +However, any subclass of `FooError` will have to manually set the prototype as well. +For runtimes that don't support [`Object.setPrototypeOf`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/setPrototypeOf), you may instead be able to use [`__proto__`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto). + +Unfortunately, [these workarounds will not work on Internet Explorer 10 and prior](https://docs.microsoft.com/en-us/archive/microsoft-edge/legacy/developer/dev-guide/whats-new/javascript-version-information). +One can manually copy methods from the prototype onto the instance itself (i.e. `FooError.prototype` onto `this`), but the prototype chain itself cannot be fixed. + +## Literal types are inferred by default for `const` variables and `readonly` properties + +String, numeric, boolean and enum literal types are not inferred by default for `const` declarations and `readonly` properties. This means your variables/properties an have more narrowed type than before. This could manifest in using comparison operators such as `===` and `!==`. + +**Example** + +```ts +const DEBUG = true; // Now has type `true`, previously had type `boolean` + +if (DEBUG === false) { /// Error: operator '===' can not be applied to 'true' and 'false' + ... +} +``` + +**Recommendation** + +For types intentionally needed to be wider, cast to the base type: + +```ts +const DEBUG = true; // type is `boolean` +``` + +## No type narrowing for captured variables in functions and class expressions + +String, numeric and boolean literal types will be inferred if the generic type parameter has a constraint of `string`,`number` or `boolean` respectively. Moreover the rule of failing if no best common super-type for inferences in the case of literal types if they have the same base type (e.g. `string`). + +**Example** + +```ts +declare function push(...args: T[]): T; + +var x = push("A", "B", "C"); // inferred as "A" | "B" | "C" in TS 2.1, was string in TS 2.0 +``` + +**Recommendation** + +Specify the type argument explicitly at call site: + +```ts +var x = push("A", "B", "C"); // x is string +``` + +## Implicit-any error raised for un-annotated callback arguments with no matching overload arguments + +Previously the compiler silently gave the argument of the callback (`c` below) a type `any`. The reason is how the compiler resolves function expressions while doing overload resolution.Starting with TypeScript 2.1 an error will be reported under `--noImplicitAny`. + +**Example** + +```ts +declare function func(callback: () => void): any; +declare function func(callback: (arg: number) => void): any; + +func(c => { }); +``` + +**Recommendation** + +Remove the first overload, since it is rather meaningless; the function above can still be called with a call back with 1 or 0 required arguments, as it is safe for functions to ignore additional arguments. +```ts +declare function func(callback: (arg: number) => void): any; + +func(c => { }); +func(() => { }); +``` + +Alternatively, you can either specify an explicit type annotation on the callback argument: + +```ts +func((c:number) => { }); +``` + +## Comma operators on side-effect-free expressions is now flagged as an error + +Mostly, this should catch errors that were previously allowed as valid comma expressions. + +**Example** + +```ts +let x = Math.pow((3, 5)); // x = NaN, was meant to be `Math.pow(3, 5)` + +// This code does not do what it appears to! +let arr = []; +switch(arr.length) { + case 0, 1: + return 'zero or one'; + default: + return 'more than one'; +} +``` + +**Recommendation** + +`--allowUnreachableCode` will disable the warning for the whole compilation. Alternatively, you can use the `void` operator to suppress the error for specific comma expressions: + +```ts +let a = 0; +let y = (void a, 1); // no warning for `a` +``` + +## Changes to DOM API's in the standard library + +* **Node.firstChild**, **Node.lastChild**, **Node.nextSibling**, **Node.previousSibling**, **Node.parentElement** and **Node.parentNode** are now `Node | null` instead of `Node`. + + See [#11113](https://github.com/Microsoft/TypeScript/issues/11113) for more details. + + Recommendation is to explicitly check for `null` or use the `!` assertion operator (e.g. `node.lastChild!`). + +# TypeScript 2.0 + +For full list of breaking changes see the [breaking change issues](https://github.com/Microsoft/TypeScript/issues?q=is%3Aissue+milestone%3A%22TypeScript+2.0%22+label%3A%22Breaking+Change%22+is%3Aclosed). + +## No type narrowing for captured variables in functions and class expressions + +Type narrowing does not cross function and class expressions, as well as lambda expressions. + +**Example** + +```ts +var x: number | string; + +if (typeof x === "number") { + function inner(): number { + return x; // Error, type of x is not narrowed, c is number | string + } + var y: number = x; // OK, x is number +} +``` + +In the previous pattern the compiler can not tell when the callback will execute. Consider: + +```ts +var x: number | string = "a"; +if (typeof x === "string") { + setTimeout(() => console.log(x.charAt(0)), 0); +} +x = 5; +``` + +It is wrong to assume `x` is a `string` when `x.charAt()` is called, as indeed it isn't. + +**Recommendation** + +Use constants instead: + +```typescript +const x: number | string = "a"; +if (typeof x === "string") { + setTimeout(() => console.log(x.charAt(0)), 0); +} +``` + +## Generic type parameters are now narrowed + +**Example** + +```ts +function g(obj: T) { + var t: T; + if (obj instanceof RegExp) { + t = obj; // RegExp is not assignable to T + } +} +``` + +**Recommendation** +Either declare your locals to be a specific type and not the generic type parameter, or use a type assertion. + +## Getters with no setters are automatically inferred to be `readonly` properties + +**Example** + +```ts +class C { + get x() { return 0; } +} + +var c = new C(); +c.x = 1; // Error Left-hand side is a readonly property +``` + +**Recommendation** + +Define a setter or do not write to the property. + +## Function declarations not allowed in blocks in strict mode + +This is already a run-time error under strict mode. Starting with TypeScript 2.0, it will be flagged as a compile-time error as well. + +**Example** + +```ts +if( true ) { + function foo() {} +} + +export = foo; +``` + +**Recommendation** + +Use function expressions instead: + +```ts +if( true ) { + const foo = function() {} +} +``` + +## `TemplateStringsArray` is now immutable + +ES2015 tagged templates always pass their tag an immutable array-like object that has a property called `raw` (which is also immutable). +TypeScript names this object the `TemplateStringsArray`. + +Conveniently, `TemplateStringsArray` was assignable to an `Array`, so it's possible users took advantage of this to use a shorter type for their tag parameters: + +```ts +function myTemplateTag(strs: string[]) { + // ... +} +``` + +However, in TypeScript 2.0, the language now supports the `readonly` modifier and can express that these objects are immutable. +As a result, `TemplateStringsArray` has also been made immutable, and is no longer assignable to `string[]`. + +**Recommendation** + +Use `TemplateStringsArray` explicitly (or use `ReadonlyArray`). + +# TypeScript 1.8 + +For full list of breaking changes see the [breaking change issues](https://github.com/Microsoft/TypeScript/issues?q=is%3Aissue+milestone%3A%22TypeScript+1.8%22+label%3A%22Breaking+Change%22+is%3Aclosed). + +## Modules are now emitted with a `"use strict";` prologue + +Modules were always parsed in strict mode as per ES6, but for non-ES6 targets this was not respected in the generated code. Starting with TypeScript 1.8, emitted modules are always in strict mode. This shouldn't have any visible changes in most code as TS considers most strict mode errors as errors at compile time, but it means that some things which used to silently fail at runtime in your TS code, like assigning to `NaN`, will now loudly fail. You can reference the [MDN Article](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode) on strict mode for a detailed list of the differences between strict mode and non-strict mode. + +To disable this behavior, pass `--noImplicitUseStrict` on the command line or set it in your tsconfig.json file. + +## Exporting non-local names from a module + +In accordance with the ES6/ES2015 spec, it is an error to export a non-local name from a module. + +**Example** + +```ts +export { Promise }; // Error +``` + +**Recommendation** + +Use a local variable declaration to capture the global name before exporting it. + +```ts +const localPromise = Promise; +export { localPromise as Promise }; +``` + +## Reachability checks are enabled by default + +In TypeScript 1.8 we've added a set of [reachability checks](https://github.com/Microsoft/TypeScript/pull/4788) to prevent certain categories of errors. Specifically + +1. check if code is reachable (enabled by default, can be disabled via `allowUnreachableCode` compiler option) + ```ts + function test1() { + return 1; + return 2; // error here + } + + function test2(x) { + if (x) { + return 1; + } + else { + throw new Error("NYI") + } + var y = 1; // error here + } + ``` +2. check if label is unused (enabled by default, can be disabled via `allowUnusedLabels` compiler option) + ```ts + l: // error will be reported - label `l` is unused + while (true) { + } + + (x) => { x:x } // error will be reported - label `x` is unused + ``` +3. check if all code paths in function with return type annotation return some value (disabled by default, can be enabled via `noImplicitReturns` compiler option) + + ```ts + // error will be reported since function does not return anything explicitly when `x` is falsy. + function test(x): number { + if (x) return 10; + } + ``` +4. check if control flow falls through cases in switch statement (disabled by default, can be enabled via `noFallthroughCasesInSwitch` compiler option). Note that cases without statements are not reported. + + ```ts + switch(x) { + // OK + case 1: + case 2: + return 1; + } + switch(x) { + case 1: + if (y) return 1; + case 2: + return 2; + } + ``` + +If these errors are showing up in your code and you still think that scenario when they appear is legitimate you can suppress errors with compiler options. + +## `--module` is not allowed alongside `--outFile` unless `--module` is specified as one of `amd` or `system`. + +Previously specifying both while using modules would result in an empty `out` file and no error. + +## Changes to DOM API's in the standard library + +* **ImageData.data** is now of type `Uint8ClampedArray` instead of `number[]`. See [#949](https://github.com/Microsoft/TypeScript/issues/949) for more details. +* **HTMLSelectElement .options** is now of type `HTMLCollection` instead of `HTMLSelectElement`. See [#1558](https://github.com/Microsoft/TypeScript/issues/1558) for more details. +* **HTMLTableElement.createCaption**, **HTMLTableElement.createTBody**, **HTMLTableElement.createTFoot**, **HTMLTableElement.createTHead**, **HTMLTableElement.insertRow**, **HTMLTableSectionElement.insertRow**, and **HTMLTableElement.insertRow** now return `HTMLTableRowElement` instead of `HTMLElement`. See [#3583](https://github.com/Microsoft/TypeScript/issues/3583) for more details. +* **HTMLTableRowElement.insertCell** now return `HTMLTableCellElement` instead of `HTMLElement`. See [#3583](https://github.com/Microsoft/TypeScript/issues/3583) for more details. +* **IDBObjectStore.createIndex** and **IDBDatabase.createIndex** second argument is now of type `IDBObjectStoreParameters` instead of `any`. See [#5932](https://github.com/Microsoft/TypeScript/issues/5932) for more details. +* **DataTransferItemList.Item** returns type now is `DataTransferItem` instead of `File`. See [#6106](https://github.com/Microsoft/TypeScript/issues/6106) for more details. +* **Window.open** return type now is `Window` instead of `any`. See [#6418](https://github.com/Microsoft/TypeScript/issues/6418) for more details. +* **WeakMap.clear** as removed. See [#6500](https://github.com/Microsoft/TypeScript/issues/6500) for more details. + +## Disallow `this` accessing before super-call +ES6 disallows accessing `this` in a constructor declaration. + +For example: +```typescript +class B { + constructor(that?: any) {} +} + +class C extends B { + constructor() { + super(this); // error; + } +} + +class D extends B { + private _prop1: number; + constructor() { + this._prop1 = 10; // error + super(); + } +} +``` + +# TypeScript 1.7 + +For full list of breaking changes see the [breaking change issues](https://github.com/Microsoft/TypeScript/issues?q=is%3Aissue+milestone%3A%22TypeScript+1.7%22+label%3A%22breaking+change%22). + +## Changes in inferring the type from `this` + +In a class, the type of the value `this` will be inferred to the `this` type. +This means subsequent assignments from values the original type can fail. + +**Example:** + +```TypeScript +class Fighter { + /** @returns the winner of the fight. */ + fight(opponent: Fighter) { + let theVeryBest = this; + if (Math.rand() < 0.5) { + theVeryBest = opponent; // error + } + return theVeryBest + } +} +``` + +**Recommendations:** + +Add a type annotation: + +```TypeScript +class Fighter { + /** @returns the winner of the fight. */ + fight(opponent: Fighter) { + let theVeryBest: Fighter = this; + if (Math.rand() < 0.5) { + theVeryBest = opponent; // no error + } + return theVeryBest + } +} +``` + +## Automatic semicolon insertion after class member modifiers + +The keywords `abstract, public, protected` and `private` are *FutureReservedWords* in ECMAScript 3 and are subject to automatic semicolon insertion. Previously, TypeScript did not insert semicolons when these keywords were on their own line. Now that this is fixed, `abstract class D` no longer correctly extends `C` in the following example, and instead declares a concrete method `m` and an additional property named `abstract`. + +Note that `async` and `declare` already correctly did ASI. + +**Example:** + +```TypeScript +abstract class C { + abstract m(): number; +} +abstract class D extends C { + abstract + m(): number; +} +``` + +**Recommendations:** + +Remove line breaks after keywords when defining class members. In general, avoid relying on automatic semicolon insertion. + +# TypeScript 1.6 + +For full list of breaking changes see the [breaking change issues](https://github.com/Microsoft/TypeScript/issues?q=is%3Aissue+milestone%3A%22TypeScript+1.6%22+label%3A%22breaking+change%22). + +## Strict object literal assignment checking + +It is an error to specify properties in an object literal that were not specified on the target type, when assigned to a variable or passed for a parameter of a non-empty target type. + +This new strictness can be disabled with the [--suppressExcessPropertyErrors](https://github.com/Microsoft/TypeScript/pull/4484) compiler option. + +**Example:** + +```typescript +var x: { foo: number }; +x = { foo: 1, baz: 2 }; // Error, excess property `baz` + +var y: { foo: number, bar?: number }; +y = { foo: 1, baz: 2 }; // Error, excess or misspelled property `baz` +``` + +**Recommendations:** + +To avoid the error, there are few remedies based on the situation you are looking into: + +**If the target type accepts additional properties, add an indexer:** + +```typescript +var x: { foo: number, [x: string]: any }; +x = { foo: 1, baz: 2 }; // OK, `baz` matched by index signature +``` + +**If the source types are a set of related types, explicitly specify them using union types instead of just specifying the base type.** + +```ts +let animalList: (Dog | Cat | Turkey)[] = [ // use union type instead of Animal + {name: "Milo", meow: true }, + {name: "Pepper", bark: true}, + {name: "koko", gobble: true} +]; +``` + +**Otherwise, explicitly cast to the target type to avoid the warning message:** +```ts +interface Foo { + foo: number; +} +interface FooBar { + foo: number; + bar: number; +} +var y: Foo; +y = { foo: 1, bar: 2 }; +``` + +## CommonJS module resolution no longer assumes paths are relative + +Previously, for the files `one.ts` and `two.ts`, an import of `"one"` in `two.ts` would resolve to `one.ts` if they resided in the same directory. + +In TypeScript 1.6, `"one"` is no longer equivalent to "./one" when compiling with CommonJS. Instead, it is searched as relative to an appropriate `node_modules` folder as would be resolved by runtimes such as Node.js. For details, see [the issue that describes the resolution algorithm](https://github.com/Microsoft/TypeScript/issues/2338). + +**Example:** + +`./one.ts` +```TypeScript +export function f() { + return 10; +} +``` + +`./two.ts` +```TypeScript +import { f as g } from "one"; +``` + +**Recommendations:** + +**Fix any non-relative import names that were unintended (strongly suggested).** + +`./one.ts` +```TypeScript +export function f() { + return 10; +} +``` + +`./two.ts` +```TypeScript +import { f as g } from "./one"; +``` + +**Set the `--moduleResolution` compiler option to `classic`.** + +## Function and class default export declarations can no longer merge with entities intersecting in their meaning + +Declaring an entity with the same name and in the same space as a default export declaration is now an error; for example, + +```TypeScript +export default function foo() { +} + +namespace foo { + var x = 100; +} +``` + +and + +```TypeScript +export default class Foo { + a: number; +} + +interface Foo { + b: string; +} +``` + +both cause an error. + +However, in the following example, merging is allowed because the namespace does does not have a meaning in the value space: + +```TypeScript +export default class Foo { +} + +namespace Foo { +} +``` + +**Recommendations:** + +Declare a local for your default export and use a separate `export default` statement as so: + +```TypeScript +class Foo { + a: number; +} + +interface foo { + b: string; +} + +export default Foo; +``` + +For more details see [the originating issue](https://github.com/Microsoft/TypeScript/issues/3095). + +## Module bodies are parsed in strict mode + +In accordance with [the ES6 spec](http://www.ecma-international.org/ecma-262/6.0/#sec-strict-mode-code), module bodies are now parsed in strict mode. module bodies will behave as if `"use strict"` was defined at the top of their scope; this includes flagging the use of `arguments` and `eval` as variable or parameter names, use of future reserved words as variables or parameters, use of octal numeric literals, etc.. + +## Changes to DOM API's in the standard library + +* **MessageEvent** and **ProgressEvent** constructors now expect arguments; see [issue #4295](https://github.com/Microsoft/TypeScript/issues/4295) for more details. +* **ImageData** constructor now expects arguments; see [issue #4220](https://github.com/Microsoft/TypeScript/issues/4220) for more details. +* **File** constructor now expects arguments; see [issue #3999](https://github.com/Microsoft/TypeScript/issues/3999) for more details. + +## System module output uses bulk exports + +The compiler uses the [new bulk-export](https://github.com/ModuleLoader/es6-module-loader/issues/386) variation of the `_export` function in the System module format that takes any object containing key value pairs (optionally an entire module object for export *) as arguments instead of key, value. + +The module loader needs to be updated to [v0.17.1](https://github.com/ModuleLoader/es6-module-loader/releases/tag/v0.17.1) or higher. + +## .js content of npm package is moved from 'bin' to 'lib' folder + +Entry point of TypeScript npm package was moved from `bin` to `lib` to unblock scenarios when 'node_modules/typescript/bin/typescript.js' is served from IIS (by default `bin` is in the list of hidden segments so IIS will block access to this folder). + +## TypeScript npm package does not install globally by default + +TypeScript 1.6 removes the `preferGlobal` flag from package.json. If you rely on this behaviour please use `npm install -g typescript`. + +## Decorators are checked as call expressions + +Starting with 1.6, decorators type checking is more accurate; the compiler will checks a decorator expression as a call expression with the decorated entity as a parameter. This can cause error to be reported that were not in previous releases. + +# TypeScript 1.5 + +For full list of breaking changes see the [breaking change issues](https://github.com/Microsoft/TypeScript/issues?q=is%3Aissue+milestone%3A%22TypeScript+1.5%22+label%3A%22breaking+change%22). + +## Referencing `arguments` in arrow functions is not allowed +This is an alignment with the ES6 semantics of arrow functions. Previously arguments within an arrow function would bind to the arrow function arguments. As per [ES6 spec draft](http://wiki.ecmascript.org/doku.php?id=harmony:specification_drafts) 9.2.12, arrow functions do not have an arguments objects. +In TypeScript 1.5, the use of arguments object in arrow functions will be flagged as an error to ensure your code ports to ES6 with no change in semantics. + +**Example:** +```ts +function f() { + return () => arguments; // Error: The 'arguments' object cannot be referenced in an arrow function. +} +``` + +**Recommendations:** +```ts +// 1. Use named rest args +function f() { + return (...args) => { args; } +} + +// 2. Use function expressions instead +function f() { + return function(){ arguments; } +} +``` + +## Enum reference in-lining changes +For regular enums, pre 1.5, the compiler *only* inline constant members, and a member was only constant if its initializer was a literal. That resulted in inconsistent behavior depending on whether the enum value is initialized with a literal or an expression. Starting with Typescript 1.5 all non-const enum members are not inlined. + +**Example:** +```ts +var x = E.a; // previously inlined as "var x = 1; /*E.a*/" + +enum E { + a = 1 +} +``` + +**Recommendation:** +Add the `const` modifier to the enum declaration to ensure it is consistently inlined at all consumption sites. + +For more details see issue [#2183](https://github.com/Microsoft/TypeScript/issues/2183). + + +## Contextual type flows through `super` and parenthesized expressions +Prior to this release, contextual types did not flow through parenthesized expressions. This has forced explicit type casts, especially in cases where parentheses are *required* to make an expression parse. + +In the examples below, `m` will have a contextual type, where previously it did not. +```ts +var x: SomeType = (n) => ((m) => q); +var y: SomeType = t ? (m => m.length) : undefined; + +class C extends CBase { + constructor() { + super({ + method(m) { return m.length; } + }); + } +} +``` + +See issues [#1425](https://github.com/Microsoft/TypeScript/issues/1425) and [#920](https://github.com/Microsoft/TypeScript/issues/920) for more details. + +## DOM interface changes +TypeScript 1.5 refreshes the DOM types in lib.d.ts. This is the first major refresh since TypeScript 1.0; many IE-specific definitions have been removed in favor of the standard DOM definitions, as well as adding missing types like Web Audio and touch events. + +**Workaround:** + +You can keep using older versions of the library with newer version of the compiler. You will need to include a local copy of a previous version in your project. Here is the [last released version before this change (TypeScript 1.5-alpha)](https://github.com/Microsoft/TypeScript/blob/v1.5.0-alpha/bin/lib.d.ts). + +**Here is a list of changes:** +- Property ``selection`` is removed from type ``Document`` +- Property ``clipboardData`` is removed from type ``Window`` +- Removed interface ``MSEventAttachmentTarget`` +- Properties ``onresize``, ``disabled``, ``uniqueID``, ``removeNode``, ``fireEvent``, ``currentStyle``, ``runtimeStyle`` are removed from type ``HTMLElement`` +- Property ``url`` is removed from type ``Event`` +- Properties ``execScript``, ``navigate``, ``item`` are removed from type ``Window`` +- Properties ``documentMode``, ``parentWindow``, ``createEventObject`` are removed from type ``Document`` +- Property ``parentWindow`` is removed from type ``HTMLDocument`` +- Property ``setCapture`` does not exist anywhere now +- Property ``releaseCapture`` does not exist anywhere now +- Properties ``setAttribute``, ``styleFloat``, ``pixelLeft`` are removed from type ``CSSStyleDeclaration`` +- Property ``selectorText`` is removed from type ``CSSRule`` +- ``CSSStyleSheet.rules`` is of type ``CSSRuleList`` instead of ``MSCSSRuleList`` +- ``documentElement`` is of type ``Element`` instead of ``HTMLElement`` +- ``Event`` has a new required property ``returnValue`` +- ``Node`` has a new required property ``baseURI`` +- ``Element`` has a new required property ``classList`` +- ``Location`` has a new required property ``origin`` +- Properties ``MSPOINTER_TYPE_MOUSE``, ``MSPOINTER_TYPE_TOUCH`` are removed from type ``MSPointerEvent`` +- ``CSSStyleRule`` has a new required property ``readonly`` +- Property ``execUnsafeLocalFunction`` is removed from type ``MSApp`` +- Global method ``toStaticHTML`` is removed +- ``HTMLCanvasElement.getContext`` now returns ``CanvasRenderingContext2D | WebGLRenderingContex`` +- Removed extension types ``Dataview``, ``Weakmap``, ``Map``, ``Set`` +- ``XMLHttpRequest.send`` has two overloads ``send(data?: Document): void;`` and ``send(data?: String): void;`` +- ``window.orientation`` is of type ``string`` instead of ``number`` +- IE-specific `attachEvent` and `detachEvent` are removed from `Window` + +**Here is a list of libraries that are partly or entirely replaced by the added DOM types:** +- ``DefinitelyTyped/auth0/auth0.d.ts`` +- ``DefinitelyTyped/gamepad/gamepad.d.ts`` +- ``DefinitelyTyped/interactjs/interact.d.ts`` +- ``DefinitelyTyped/webaudioapi/waa.d.ts`` +- ``DefinitelyTyped/webcrypto/WebCrypto.d.ts`` + +For more details, please see the [full change](https://github.com/Microsoft/TypeScript/pull/2739). + +## Class bodies are parsed in strict mode + +In accordance with [the ES6 spec](http://www.ecma-international.org/ecma-262/6.0/#sec-strict-mode-code), class bodies are now parsed in strict mode. Class bodies will behave as if `"use strict"` was defined at the top of their scope; this includes flagging the use of `arguments` and `eval` as variable or parameter names, use of future reserved words as variables or parameters, use of octal numeric literals, etc.. + +# TypeScript 1.4 + +For full list of breaking changes see the [breaking change issues](https://github.com/Microsoft/TypeScript/issues?q=is%3Aissue+milestone%3A%22TypeScript+1.4%22+label%3A%22breaking+change%22). + +See [issue #868](https://github.com/Microsoft/TypeScript/issues/868) for more details about breaking changes related to Union Types + +## Multiple Best Common Type Candidates +Given multiple viable candidates from a Best Common Type computation we now choose an item (depending on the compiler's implementation) rather than the first item. + +```ts +var a: { x: number; y?: number }; +var b: { x: number; z?: number }; + +// was { x: number; z?: number; }[] +// now { x: number; y?: number; }[] +var bs = [b, a]; +``` + +This can happen in a variety of circumstances. A shared set of required properties and a disjoint set of other properties (optional or otherwise), empty types, compatible signature types (including generic and non-generic signatures when type parameters are stamped out with ```any```). + +**Recommendation** +Provide a type annotation if you need a specific type to be chosen +```ts +var bs: { x: number; y?: number; z?: number }[] = [b, a]; +``` + +## Generic Type Inference +Using different types for multiple arguments of type T is now an error, even with constraints involved: + +```ts +declare function foo(x: T, y:T): T; +var r = foo(1, ""); // r used to be {}, now this is an error +``` +With constraints: + +```ts +interface Animal { x } +interface Giraffe extends Animal { y } +interface Elephant extends Animal { z } +function f(x: T, y: T): T { return undefined; } +var g: Giraffe; +var e: Elephant; +f(g, e); +``` + +See https://github.com/Microsoft/TypeScript/pull/824#discussion_r18665727 for explanation. + +**Recommendations** +Specify an explicit type parameter if the mismatch was intentional: +```ts +var r = foo<{}>(1, ""); // Emulates 1.0 behavior +var r = foo(1, ""); // Most useful +var r = foo(1, ""); // Easiest +f(g, e); +``` +*or* rewrite the function definition to specify that mismatches are OK: +```ts +declare function foo(x: T, y:U): T|U; +function f(x: T, y: U): T|U { return undefined; } +``` + +## Generic Rest Parameters +You cannot use heterogeneous argument types anymore: + +```ts +function makeArray(...items: T[]): T[] { return items; } +var r = makeArray(1, ""); // used to return {}[], now an error +``` +Likewise for `new Array(...)` + +**Recommendations** +Declare a back-compatible signature if the 1.0 behavior was desired: +```ts +function makeArray(...items: T[]): T[]; +function makeArray(...items: {}[]): {}[]; +function makeArray(...items: T[]): T[] { return items; } +``` + +## Overload Resolution with Type Argument Inference + +```ts +var f10: (x: T, b: () => (a: T) => void, y: T) => T; +var r9 = f10('', () => (a => a.foo), 1); // r9 was any, now this is an error +``` + +**Recommendations** +Manually specify a type parameter +```ts +var r9 = f10('', () => (a => a.foo), 1); +``` + +## Strict Mode Parsing for Class Declarations and Class Expressions +ECMAScript 2015 Language Specification (ECMA-262 6th Edition) specifies that *ClassDeclaration* and *ClassExpression* are strict mode productions. +Thus, additional restrictions will be applied when parsing a class declaration or class expression. + +Examples: + +```ts +class implements {} // Invalid: implements is a reserved word in strict mode +class C { + foo(arguments: any) { // Invalid: "arguments" is not allow as a function argument + var eval = 10; // Invalid: "eval" is not allowed as the left-hand-side expression + arguments = []; // Invalid: arguments object is immutable + } +} +``` +For complete list of strict mode restrictions, please see Annex C - The Strict Mode of ECMAScript of ECMA-262 6th Edition. + + +# TypeScript 1.1 + +For full list of breaking changes see the [breaking change issues](https://github.com/Microsoft/TypeScript/issues?q=is%3Aissue+milestone%3A%22TypeScript+1.1%22+label%3A%22breaking+change%22+). + +## Working with null and undefined in ways that are observably incorrect is now an error + +Examples: + +```TypeScript +var ResultIsNumber17 = +(null + undefined); +// Operator '+' cannot be applied to types 'undefined' and 'undefined'. + +var ResultIsNumber18 = +(null + null); +// Operator '+' cannot be applied to types 'null' and 'null'. + +var ResultIsNumber19 = +(undefined + undefined); +// Operator '+' cannot be applied to types 'undefined' and 'undefined'. +``` + +Similarly, using null and undefined directly as objects that have methods now is an error + +Examples: + +```TypeScript +null.toBAZ(); + +undefined.toBAZ(); +``` + + \ No newline at end of file diff --git a/notes/Cancellation-Support-in-tsserver.md b/notes/Cancellation-Support-in-tsserver.md new file mode 100644 index 00000000..8ffd8941 --- /dev/null +++ b/notes/Cancellation-Support-in-tsserver.md @@ -0,0 +1 @@ +This page has moved to https://github.com/Microsoft/TypeScript/wiki/Standalone-Server-%28tsserver%29#cancellation \ No newline at end of file diff --git a/notes/Coding-guidelines.md b/notes/Coding-guidelines.md new file mode 100644 index 00000000..a2bcb35b --- /dev/null +++ b/notes/Coding-guidelines.md @@ -0,0 +1,94 @@ +# ***STOP READING IMMEDIATELY*** + +## THIS PAGE PROBABLY DOES **NOT** PERTAIN TO YOU. + +These are Coding Guidelines for ***Contributors to TypeScript***. +This is ***NOT*** a prescriptive guideline for the TypeScript community. +These guidelines are meant for **contributors to the TypeScript project's codebase**. +We have chosen many of them for team consistency. Feel free to adopt them for your own team. \ +\ +AGAIN: This is ***NOT*** a prescriptive guideline for the TypeScript community +-------------------- + +## **Please do not file issues about these guidelines.** + +## Names + +1. Use PascalCase for type names. +2. Do not use `I` as a prefix for interface names. +3. Use PascalCase for enum values. +4. Use camelCase for function names. +5. Use camelCase for property names and local variables. +6. Do not use `_` as a prefix for private properties. +7. Use whole words in names when possible. + +## Components +1. 1 file per logical component (e.g. parser, scanner, emitter, checker). +2. Do not add new files. :) +3. files with `.generated.*` suffix are auto-generated, do not hand-edit them. + +## Types +1. Do not export types/functions unless you need to share it across multiple components. +2. Do not introduce new types/values to the global namespace. +3. Shared types should be defined in `types.ts`. +4. Within a file, type definitions should come first. + +## `null` and `undefined` +1. Use `undefined`. Do not use null. + +## General Assumptions +1. Consider objects like Nodes, Symbols, etc. as immutable outside the component that created them. Do not change them. +2. Consider arrays as immutable by default after creation. + +## Classes +1. For consistency, do not use classes in the core compiler pipeline. Use function closures instead. + +## Flags +1. More than 2 related Boolean properties on a type should be turned into a flag. + +## Comments +1. Use JSDoc style comments for functions, interfaces, enums, and classes. + +## Strings +1. Use double quotes for strings. +2. All strings visible to the user need to be localized (make an entry in diagnosticMessages.json). + +## Diagnostic Messages +1. Use a period at the end of a sentence. +2. Use indefinite articles for indefinite entities. +3. Definite entities should be named (this is for a variable name, type name, etc..). +4. When stating a rule, the subject should be in the singular (e.g. "An external module cannot..." instead of "External modules cannot..."). +5. Use present tense. + +## Diagnostic Message Codes +Diagnostics are categorized into general ranges. If adding a new diagnostic message, use the first integral number greater than the last used number in the appropriate range. +* 1000 range for syntactic messages +* 2000 for semantic messages +* 4000 for declaration emit messages +* 5000 for compiler options messages +* 6000 for command line compiler messages +* 7000 for noImplicitAny messages + +## General Constructs + +For a variety of reasons, we avoid certain constructs, and use some of our own. Among them: + +1. Do not use `for..in` statements; instead, use `ts.forEach`, `ts.forEachKey` and `ts.forEachValue`. Be aware of their slightly different semantics. +2. Try to use `ts.forEach`, `ts.map`, and `ts.filter` instead of loops when it is not strongly inconvenient. + +## Style + +1. Use arrow functions over anonymous function expressions. +2. Only surround arrow function parameters when necessary.
For example, `(x) => x + x` is wrong but the following are correct: + - `x => x + x` + - `(x,y) => x + y` + - `(x: T, y: T) => x === y` +3. Always surround loop and conditional bodies with curly braces. Statements on the same line are allowed to omit braces. +4. Open curly braces always go on the same line as whatever necessitates them. +5. Parenthesized constructs should have no surrounding whitespace.
A single space follows commas, colons, and semicolons in those constructs. For example: + - `for (var i = 0, n = str.length; i < 10; i++) { }` + - `if (x < 10) { }` + - `function f(x: number, y: string): void { }` +6. Use a single declaration per variable statement
(i.e. use `var x = 1; var y = 2;` over `var x = 1, y = 2;`). +7. `else` goes on a separate line from the closing curly brace. +8. Use 4 spaces per indentation. diff --git a/notes/Common-Errors.md b/notes/Common-Errors.md new file mode 100644 index 00000000..416ed3e5 --- /dev/null +++ b/notes/Common-Errors.md @@ -0,0 +1 @@ +Deprecated doc \ No newline at end of file diff --git a/notes/Compiler-Internals.md b/notes/Compiler-Internals.md new file mode 100644 index 00000000..488b51e8 --- /dev/null +++ b/notes/Compiler-Internals.md @@ -0,0 +1 @@ +> ### This page has moved to https://github.com/microsoft/TypeScript-Compiler-Notes/ \ No newline at end of file diff --git a/notes/Compiler-Options.md b/notes/Compiler-Options.md new file mode 100644 index 00000000..fc20565a --- /dev/null +++ b/notes/Compiler-Options.md @@ -0,0 +1 @@ +> ### This page has moved to http://www.typescriptlang.org/docs/handbook/compiler-options.html \ No newline at end of file diff --git a/notes/Configuring-MSBuild-projects-to-use-NuGet.md b/notes/Configuring-MSBuild-projects-to-use-NuGet.md new file mode 100644 index 00000000..5789089d --- /dev/null +++ b/notes/Configuring-MSBuild-projects-to-use-NuGet.md @@ -0,0 +1,60 @@ +> **Note**: The install script will remove the default import to the `Microsoft.TypeScript.targets` file; +if you have manually edited the import before, you will need to remove it yourself **before** proceeding. +See [Removing default imports](#removing-default-imports) for more details. + +> **Note**: The Nuget package depends on the x86 version of [Visual C++ Redistributable for Visual Studio 2015] +(https://www.microsoft.com/en-us/download/details.aspx?id=48145). +This is generally already installed on your computer, but you can verify that within **Programs and Features**. + +## For major releases (https://www.nuget.org) + +* Right-Click -> Manage NuGet Packages +* Search for `Microsoft.TypeScript.MSBuild` + ![Search for NuGet package.](https://raw.githubusercontent.com/wiki/Microsoft/TypeScript/images/searchForNuGetPackage.png) + +* Hit `Install` +* When install is complete, rebuild! + + +## For Nightly drops (https://www.myget.org) + +1. Add a new Package Source + * Go to `Tools` -> `Options` -> `NuGet Package Manager` -> `Package Sources` + * Create a new Source: + * Name: `TypeScript Nightly` + * Source: `https://www.myget.org/F/typescript-preview/` + ![Add new Package Source.](https://raw.githubusercontent.com/wiki/Microsoft/TypeScript/images/addNewPackageSource.PNG) + +2. Use the new Package Source + * On Project node Right-Click -> `Manage NuGet Packages` + * Search for `Microsoft.TypeScript.MSBuild` + ![Search for NuGet package.](https://raw.githubusercontent.com/wiki/Microsoft/TypeScript/images/searchForMyGetPackage.PNG) + * Hit `Install` + * When install is complete, rebuild! + + +## Removing default imports + +* Right-Click -> `Unload Project` +* Right-Click -> `Edit ` +* Remove references to + + * `Microsoft.TypeScript.Default.props` + + The import should look something like: + + ```XML + + ``` + + * `Microsoft.TypeScript.targets` + + The import should look something like: + + ```XML + + ``` diff --git a/notes/Contributing-to-TypeScript.md b/notes/Contributing-to-TypeScript.md new file mode 100644 index 00000000..8e29f4f6 --- /dev/null +++ b/notes/Contributing-to-TypeScript.md @@ -0,0 +1,53 @@ +There are three great ways to contribute to the TypeScript project: logging bugs, submitting pull requests, and creating suggestions. + +### Logging Bugs + +To log a bug, just use the GitHub issue tracker. Confirmed bugs will be labelled with the `Bug` label. Please include code to reproduce the issue and a description of what you expected to happen. + +### Pull Requests + +Before we can accept a pull request from you, you'll need to sign the Contributor License Agreement (CLA). See the "Legal" section of the [CONTRIBUTING.md guide](https://github.com/Microsoft/TypeScript/blob/main/CONTRIBUTING.md). That document also outlines the technical nuts and bolts of submitting a pull request. Be sure to follow our [[Coding Guidelines|coding-guidelines]]. + +You can learn more about the compiler's codebase at https://github.com/microsoft/TypeScript-Compiler-Notes/ + +### Suggestions + +We're also interested in your feedback in future of TypeScript. You can submit a suggestion or feature request through the issue tracker. To make this process more effective, we're asking that these include more information to help define them more clearly. Start by reading the [[TypeScript Design Goals]] and refer to [[Writing Good Design Proposals]] for information on how to write great feature proposals. + +### Issue Tracking 101 + +Unlabelled issues haven't been looked at by a TypeScript coordinator. You can expect to see them labelled within a few days of being logged. + +Issues with the `Bug` label are considered to be defects. Once they have the `Bug` label, they'll either be assigned to a TypeScript developer and assigned a milestone, or put in the Community milestone, indicating that we're accepting pull requests for this bug. Community bugs are a great place to start if you're interested in making a code contribution to TypeScript. + +We'll be using Labels to track the status of suggestions or feature requests. You can expect to see the following: + * `Suggestion`: We consider this issue to not be a bug per se, but rather a design change or feature of some sort. Any issue with this label should have at least one more label from the list below + * `Needs Proposal`: A full write-up is needed to explain how the feature should work + * `Needs More Info`: A proposal exists, but there are follow-up questions that need to be addressed + * `In Discussion`: This is being discussed by the TypeScript design team. You can expect this phase to take at least a few weeks, depending on our schedule + * `Ready to Implement`: The proposal is accepted and has been designed enough that it can be implemented now + * `help wanted`: We are accepting pull requests that fully implement this feature + * `Committed`: We have allocated time on the team schedule to implement this feature + +Declined suggestions will have the `Declined` label along with one of the following: + * `Out of Scope`: Is outside the scope of the TypeScript compiler; would be better implemented as a separate tool or extension rather than a change to TypeScript itself + * `Too Complex`: The amount of complexity that this (and its future implications) would introduce is not justified by the amount of value it adds to the language + * `Breaking Change`: Would meaningfully break compatibility with JavaScript or a previous version of TypeScript, or would prevent us from implementing known future ECMAScript proposals + * `By Design`: This aspect of the language is an intentional design decision + +Issues that are not bugs or suggestions will be labelled appropriately (`Question`, `By Design`, `External`) and closed. Please use [Stack Overflow](http://stackoverflow.com/questions/tagged/typescript) for TypeScript questions. + +### Discussion + +In order to keep the conversation clear and transparent, limit discussion to English and keep things on topic with the issue. +Be considerate to others and try to be courteous and professional at all times. + +### Documentation + +For any new features, please: +* Add a link to the Roadmap: https://github.com/Microsoft/TypeScript/wiki/Roadmap +* Add a blurb to what's new page: https://github.com/Microsoft/TypeScript/wiki/What%27s-new-in-TypeScript +* Add a section to the Handbook, if big enough: https://github.com/Microsoft/TypeScript-Handbook +* For breaking changes: + * Add a breaking change notice: https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes + * or to the API breaking changes pages: https://github.com/Microsoft/TypeScript/wiki/API-Breaking-Changes diff --git a/notes/Debugging-Language-Service-in-VS-Code.md b/notes/Debugging-Language-Service-in-VS-Code.md new file mode 100644 index 00000000..91a04e72 --- /dev/null +++ b/notes/Debugging-Language-Service-in-VS-Code.md @@ -0,0 +1,134 @@ +VS Code is designed around an extension model. TypeScript provides a server called TSServer that provides information which supports quick-info, completions, etc., then VS Code acts as a client which queries the server when this information is needed. + +For example, VS Code queries TSServer for quick-info when the user's mouse hovers over a variable by sending a message to TSServer. TSServer will respond with information such as the appropriate type, and the styling to apply to the text that describes the type. + +Organizationally, the client-side code for communicating with the TypeScript server lives in [`extensions/typescript-language-features`](https://github.com/Microsoft/vscode/tree/master/extensions/typescript-language-features) in [the VS Code repository](https://github.com/Microsoft/vscode).1 + +Meanwhile, the server-side code lives in `src/services` and `src/server` of [the TypeScript repository](https://github.com/Microsoft/TypeScript). + +## Using stable VS Code to Debug Stable TSServer + +There are two steps to this: + +- Launch VS Code with an extra environment variable, and different user profile. +- Connect to this VS Code's TSServer. + +To launch VS Code with a different profile and a debug copy of TSServer: + +```sh +# Sets the TSServer port to 5667, this can be any number +# Sets the user-data directory to be ~/.vscode-debug/ instead of ~/.vscode/ + +TSS_DEBUG=5667 code --user-data-dir ~/.vscode-debug/ +``` + +This will open VS Code as a separate app from your current one, it may have some of your extensions but not your settings. As long as you consistently use the above command, then you can save settings for debugging between sessions. + +Optionally you can use `TSS_DEBUG_BRK` (i.e. `TSS_DEBUG_BRK=5567`) to have the TSServer wait for your debugger before launching. + +This will launch a debug TSServer which you can connect to from inside the TypeScript codebase. Open up the TypeScript codebase, and look at the debugging panel. At the top, look to see if there is a drop-down item for debugging by Attaching to VS Code TSServer then select that. + +If there isn't, copy the template of `.vscode/launch.template.json` to `.vscode/launch.json` and it should show up. + +Select the "Attach by ..." option in the dropdown for debugging and hit the play button, it will ask you to choose a node instance to connect to. In the above example we used the port 5667, look for that and select it. + +That should have you connected to the TSServer for the debugging app version of VS Code while you work in the production version. + +## Using Stable VS Code with Development TSServer + + +VS Code chooses where to launch TSServer from via the setting: `typescript.tsdk`. Continuing from above, if you want to have your TSServer use a local copy of TypeScript then change this setting (in `.vscode/settings.json` or your user JSON settings) to: + +```json +{ + "typescript.tsdk": "/path/to/repo/TypeScript/built/local" +} +``` + +This version of TypeScript may not be selected automatically; ensure that the above is being used by running the "TypeScript: Select TypeScript Version..." command in the command palette (Ctrl+Shift+P or Cmd+Shift+P). + +This is probably enough for most contributors, but if you are doing heavy duty VS Code and TypeScript work, you may want to carry on. + +--- + +## Development VS Code with Development TSServer + +We will use a stable version of VS Code to debug a development version of VS Code running against a development version of TSServer. + +1. Download/install a stable version of vs code. +2. Follow the instructions to [setup a development version of VS Code](https://github.com/Microsoft/vscode/wiki/How-to-Contribute).2 +3. Clone the TypeScript repo locally, and follow the instructions on [building TypeScript](https://github.com/Microsoft/TypeScript#building). +4. [Update the User Settings](https://code.visualstudio.com/docs/languages/typescript#_using-newer-typescript-versions) in the development version of VS Code, to point to the `built/local` directory of your local TypeScript repository. + + This will look something like the following: + + ```json + { + "typescript.tsdk": "/path/to/repo/TypeScript/built/local" + } + ``` + + You may instead update this in the Workspace Settings for a project as well, but you will have to remember that the development version of TSServer will only be in effect within that project. + +From here, there are different steps for debugging the client- and server-side, respectively. + +## Debugging tsserver (server-side) + +1. Choose an available port to debug TSServer using either of the following two methods (in the rest of this guide, we assume you chose 5859): + * In a shell, export the `TSS_DEBUG` environment variable to an open port. We will run the development VS Code instance from within that shell. + + For most Unix-like shells (e.g. bash), this will be something like + + ```sh + export TSS_DEBUG=5859 + ``` + + For PowerShell, this is something like + + ```posh + $env:TSS_DEBUG = 5859 + ``` + + * Alternatively, manually edit `extensions/typescript/src/typescriptServiceClient.ts` in your development-side VS Code, setting the port to an open one. + +2. Update `launch.json` with an option to attach to the node instance, with sourcemaps from your `built/local` folder. + + For VS Code v1.13.1+ and Node v8.0+, your `launch.json` might look like the following: + + ```json5 + { + "version": "0.2.0", + "configurations": [ + // Other configs + { + "name": "Attach to TS Server", + "type": "node", + "request": "attach", + "protocol": "inspector", + "port": 5859, + "sourceMaps": true, + "outFiles": ["/path/to/repo/TypeScript/built/local"], + } + ] + } + ``` + + For the same versions of Code, but older versions of Node (e.g. 6.x), you'll need to set `"protocol"` to be `"legacy"`. + +3. Launch an instance of your development VS Code, and open a TypeScript file. +4. Launch your stable-release version of VS Code. +5. Attach the stable VS Code instance to the development instance. + +## Debugging the Extension Host (client-side) + +3) Launch an instance of development vs code. + +4) Launch an instance of stable vs code. + +5) Attach the stable vs code instance to the development instance. + + +--- +1 In particular, the built-in extension spawns the node instance that loads tsserver via the call to electron.fork() in `extensions/typescript/src/typescriptServiceClient.ts`. + +2 If you are on Linux, be sure to increase the number of file watchers per the fix for ENOSPC [errors](https://github.com/Microsoft/vscode/wiki/How-to-Contribute#incremental-build). for opening medium-large projects like Typescript, the default limit of 8192 is almost certainly too small. diff --git a/notes/Docker-Quickstart.md b/notes/Docker-Quickstart.md new file mode 100644 index 00000000..9a0451c4 --- /dev/null +++ b/notes/Docker-Quickstart.md @@ -0,0 +1,341 @@ +# Using Docker, the short, short version + +> "Short" is not a joke, it's because I used many examples which is why +> this text is much longer than what you need. To make it short, find +> the first example that fits your needs and use it. + +## Quick highlevel overview + +Docker is essentially a way to run stuff in a local sandboxed +environment. The environment is specified by a *docker image*, and its +main component is a snapshot of all files that are needed to run in, in +the form of "layers", each saved as a tar archive (and it's implemented +as [UnionFS](https://en.wikipedia.org/wiki/UnionFS)). + +> Docker is not a VM, but often confused as one. Images are +> linux-based, and therefore Docker on Windows works by installing a +> tiny Hyper-V Linux VM to run on (but that is shared for all docker +> uses, it's not starting a VM for each run). + +When you run an image, the running sandbox is called a *container*. +These container are based on the image which is the initial state (files +etc), and on top of that there are any changes that the current +execution created (FS changes, running process/es, etc). When container +is done running, *all of that* usually disappears, making it very +convenient to run random stuff without affecting your setup. (It is +possible to save containers, but usually they're removed after use.) + +## Quick examples + +You need to [install +docker](https://www.docker.com/products/docker-desktop) to try the +following examples. The installer itself is generally well behaved and +will tell you what needs to be done to make it work (eg, turning on +windows features like hyper-v or the wsl2 backend). There are also +installers for macs and for linux (the latter being a system daemon +rather than a tiny vm). + +Once installed, you can use the `docker` command to do stuff. It has +the usual `docker 〈verb〉 args...` format. On windows, it works fine +in all forms: powershell, vscode, and even in a cmd box. The main (and +possibly the only) verb you need to know about is `run`: + +``` +docker run -it --rm node +``` + +This drops you into a running `node` container. (Ctrl+D is the +canonical EOF-thing in unix, use it to exit the running process and +therefore the container.) + +* `run`: start running a container for the specified image. The image + will be pulled in on first use. + +* `-it`: interactive run (short for `--interactive --tty`, the latter is + a unix thing) + +* `--rm`: delete the container when done (you can drop this if you want + to keep the results, but usually you want to include it) + +* `node`: the name of the image we want to run (there are + [many](https://hub.docker.com/), enough that most random guesses for + "the thing you want to try" will work) + +``` +docker run -it --rm node:12 +``` + +Image names are tagged — this is similar to the above, but now I'm +specifying that I want to use the `12` tag. When you don't specify a +tag as in the above, you get the default of `:latest`. + +> Tags are not permanently fixed (especially not `latest`). To update a +> tag (eg, a new node version is published), you can use `docker pull +> node` to update it. Similarly, `node:12` is a tag that points at the +> most recent 12.x version. + +But this is still just drops you into a running `node`, what if you want +to do something before starting it, like installing some suspicious +package? + +``` +docker run -it --rm node bash +``` + +Here I added a `bash` at the end, overriding what the `node` image runs +by default. Now I get a `bash` prompt, and I can do whatever I want: +`npm install` stuff (locally or globally), `apt install` OS packages +(you'll need to `apt update` first to get the package directory), and +even `rm /bin/*` — it's all completely safe, and everything will +disappear when the container is done. + +But if you know even a little about linux, you'll recognize that this is +a kind of an overkill: you start at the root of the filesystem, and as +the `root` user. This could be significantly different from actual use. +For example, I run into a weird new `1line-aa` npm package, with no +visible information about how it's working, and I want to try it as a +user. + +``` +docker run -it --rm node bash +$ su -l node +$ npm install 1line-aa +``` + +One way to do this is to run `su -l node` in the container, which starts +a new shell for the `node` user (which the node image includes). Since +this process is started from the first one, you'll need to Ctrl+D twice +to get out of the container (or thrice if you start `node`). + +``` +docker run -it --rm -u node -w /home/node node bash +``` + +Another way to do this directly is to add: + +* `-u node`: start as the `node` user + +* `-w /home/node`: in its home directory + +So far all of these examples left nothing behind, but what if you *want* +to collect some of the resulting files? + +``` +docker run -it --rm -v c:\foo:/work node bash +``` + +* `-v c:\foo:/work`: mount the `c:\foo` directory onto `/work` in the + container + +This means that in the container you can `cd /work` and do whatever you +want there: since it's a mounted directory, everything will actually +happen in your `c:\foo` directory (which will be created if it doesn't +exist). It doesn't matter that the file owner inside the container is +`root`, since on a Windows host side, it's all running as your Windows +user. This is *not* the case if you're using docker on linux: in that +case, `root` in the container will create files that belong to `root` on +the host. In any case, switching to the `node` user (as done above) is +preferable. + +## Complicated example 1: tsserverfuzzer + +This is a more involved example: running the +[fuzzer](https://github.com/microsoft/tsserverfuzzer). First, clone the +repository — the `node` image includes `git` so you can do it in the +container, but you're probably more comfortable with your usual +environment. You'll probably use vscode or whatever... something like + +``` +c:\> cd work +C:\work> git clone ...tsserverfuzzer... +C:\work> cd tsserverfuzzer +C:\work\tsserverfuzzer> docker run -it --rm -v %cd%:/fuzzer -w /fuzzer -u node node bash +``` + +* `-it --rm`: interactive, dispose after use + +* `-v %cd%:/fuzzer`: mount the current directory as `/fuzzer` in the + container (in powershell, use `$pwd` instead of `%cd%`) + +* `-w /fuzzer`: and work in there + +* `-u node`: as the `node` user + +``` +node@...:/fuzzer$ npm install +... +node@...:/fuzzer$ npm run build +... +node@...:/fuzzer$ git status +... +node@...:/fuzzer$ node lib/Fuzzer/main.js +``` + +You can now do the usual things, even `git` commands (since the file +format is the same — just be careful of sneaky EOL translation). + +I you did all of this, the `git status` should show just a change in +`package-lock.json`, and the last execution got stuck waiting for a +debugger to connect. Ctrl+C to abort it, and Ctrl+D to exit the +container. + +``` +docker run ...same... -p 9229:9242 node bash +``` + +It's possible to forward ports from the container to the host, and it's +similar to the `-v` flag with the same meaning to the two sides of the +colon: here we're saying that port 9242 in the container is exposed as +port 9229 on the host. Once you do that, you can skip the building +(since the built files are still in the directory on your host) and go +straight to the `node` command. + +... except that this won't work either. This is because the debugger +listens on `127.0.0.1:9242` (and it tells you that), which means that it +only accepts connections from `localhost` which is the container. We're +connecting from what looks to the container like a different machine, so +we need to allow that. To do this, open +`C:\work\tsserverfuzzer\Fuzzer\main.ts` in your editor (outside the +container!) and change `'--inspect-brk=9242'` to +`'--inspect-brk=0.0.0.0:9242'` (the `0.0.0.0` tells it to listen to +anyone). + +The container sees the file modification, so you don't need to restart +it, you can just run `npm build` again, and re-run. + +``` +docker run ...same... node node lib/Fuzzer/main.js +``` + +When you want to run the already-built fuzzer later, you can start it +directly. The `node node` looks confusing, but the first one is the +name of the image, and following it is the `node` command that you want +to run in the container instead of starting an interactive repl. + +``` +docker run ...same... -e GitHubAuthenticationKey=%tok% node node lib/Fuzzer/main.js +``` + +At some point you'll find that it needs a GH key in the +`$GitHubAuthenticationKey` environment variable. The `-e VAR=VAL` flag +sets such a value, and in this case we're using a Windows `%tok%` as the +value. (And something like `$env:tok` in powershell.) + +Since it's running the node code directly, a Ctrl+C will stop it and +exit the container immediately. + +## Complicated example 2: TypeScriptErrorDeltas + +There's enough verbiage above to run it, but a few more useful bits that +are relevant in this case: + +``` +docker run ... -v %USERPROFILE%\.npmrc:/home/node/.npmrc:ro ... +``` + +You'll find that you need an npm authentication key to be able to `npm +install` this thing. Assuming that you have the key in your +`C:\Users\foo\.npmrc`, you can re-use your `.npmrc` in the container. +There are two new things here: + +* Container mounts don't have to be directories, you can mount a single + file as this is doing. + +* An access mode can follow a second `:`, use `rw` (the default) for + read-write or `ro` read-only. In this example using `:ro` ensures + that the container cannot modify the windows `.npmrc` file. + +``` +C:\...> docker run -it --rm ... node bash +# apt update; apt install sudo +# node /work/index.js 1 3.3 3.4 false +``` + +One problem with running this code is that it requires having `sudo`, +but the `node` image is based on a minimal linux so it doesn't have it. +One way to do it is to fix the code to not use `sudo` if it's running as +root ... but a way around it is to start the container with `bash`, and +run the two `apt` commands to get `sudo` installed. (In the case of +this `TypeScriptErrorDeltas` code, there is something else that is +needed: see "Privileged runs" below.) + +It is obviously tedious to do this installation every time you want to +run it — ignoring changing the code to not require extra packages, it is +pretty easy to build an image yourself. But I'll finish the quick part +here. + +## Extras + +### Privileged runs + +A docker container is an image running in a sandboxed environment that +is restricted in several ways (like seeing its own FS and network). +There are, however, cases where linux functionality is needed from the +kernel — and mounting things (when you're already *in* the container) is +one such case that is normally blocked. Docker has a bunch of +"capabilities" that are off by default and can be turned on if needed. +In cases like `TypeScriptErrorDeltas`, where you're running known +non-malicious code, you can just enable all of them by adding a +`--privileged` flag. + +### `docker build` + +The `build` verb can be used with a `Dockerfile` which specifies a +recipe for creating an image. For example, it's easy to make an image +that is based on the `node` image, but has a few more os packages +installed, and defaults to a specific directory, user, and command to +run. There's lots of examples around, but in general I'll be happy to +explain how to create any image that anyone might need. + +### `docker ps` + +This is a useful command to see a list of running docker containers. +Usually this should be empty, but you might press some wrong key (like +Ctrl+Z, which suspends a process) and end up with a stray process. Use +this to see such processes, and kill them with `docker rm -f +〈container-id〉`. + +``` +const orGUI = + "Or, as long as you're a gui-dependent windows user," + + "just use the docker gui..."; +``` + +`console.log(orGUI);` + +### `docker exec` + +The process that gets to run on a `docker run` is not the only thing +that runs. Subprocesses can run in the container, of course, but in +addition to that you can start another process in the context of a +running container. This is useful, for example, if you started a +container as the `node` user, and you need to install some os package, +but you don't want to start from scratch. + +``` +C:\> docker ps +... node id ... +C:\> docker exec -it 123 bash +``` + +To do this, use `docker ps` to find your container's id, then use +`docker exec` to start a `bash` process in it. It is somewhat similar +to `run` except that it expects a running container id. (Or names, +since you can name running containers, because why not add features.) + +`console.log(orGUI);` + +### `docker system prune` + +You might end up with random stuff that sticks around for whatever +reason. A running or a suspeded container, stray images since you +played with building your own image, or whatever. + +``` +docker system prune -f +``` + +This will remove any such stuffs. The `-f` makes it just remove the +unnecessary stuff rather than ask you for confirmation. + +`console.log(orGUI);` diff --git a/notes/FAQ.md b/notes/FAQ.md new file mode 100644 index 00000000..eb2ff864 --- /dev/null +++ b/notes/FAQ.md @@ -0,0 +1,1515 @@ +# FAQs + + + + + + + + - [Common "Bugs" That Aren't Bugs](#common-bugs-that-arent-bugs) + - [Common Feature Requests](#common-feature-requests) + - [Type System Behavior](#type-system-behavior) + - [What is structural typing?](#what-is-structural-typing) + - [What is type erasure?](#what-is-type-erasure) + - [Why are getters without setters not considered read-only?](#why-are-getters-without-setters-not-considered-read-only) + - [Why are function parameters bivariant?](#why-are-function-parameters-bivariant) + - [Why are functions with fewer parameters assignable to functions that take more parameters?](#why-are-functions-with-fewer-parameters-assignable-to-functions-that-take-more-parameters) + - [Why are functions returning non-`void` assignable to function returning `void`?](#why-are-functions-returning-non-void-assignable-to-function-returning-void) + - [Why are all types assignable to empty interfaces?](#why-are-all-types-assignable-to-empty-interfaces) + - [Can I make a type alias nominal?](#can-i-make-a-type-alias-nominal) + - [How do I prevent two types from being structurally compatible?](#how-do-i-prevent-two-types-from-being-structurally-compatible) + - [How do I check at run-time if an object implements some interface?](#how-do-i-check-at-run-time-if-an-object-implements-some-interface) + - [Why doesn't this incorrect cast throw a runtime error?](#why-doesnt-this-incorrect-cast-throw-a-runtime-error) + - [Why don't I get type checking for `(number) => string` or `(T) => T`?](#why-dont-i-get-type-checking-for-number--string-or-t--t) + - [Why am I getting an error about a missing index signature?](#why-am-i-getting-an-error-about-a-missing-index-signature) + - [Why am I getting `Supplied parameters do not match any signature` error?](#why-am-i-getting-supplied-parameters-do-not-match-any-signature-error) + - [Functions](#functions) + - [Why can't I use `x` in the destructuring `function f({ x: number }) { /* ... */ }`?](#why-cant-i-use-x-in-the-destructuring-function-f-x-number------) + - [Classes](#classes) + - [Why do these empty classes behave strangely?](#why-do-these-empty-classes-behave-strangely) + - [When and why are classes nominal?](#when-and-why-are-classes-nominal) + - [Why does `this` get orphaned in my instance methods?](#why-does-this-get-orphaned-in-my-instance-methods) + - [What's the difference between `Bar` and `typeof Bar` when `Bar` is a `class`?](#whats-the-difference-between-bar-and-typeof-bar-when-bar-is-a-class) + - [Why do my derived class property initializers overwrite values set in the base class constructor?](#why-do-my-derived-class-property-initializers-overwrite-values-set-in-the-base-class-constructor) + - [What's the difference between `declare class` and `interface`?](#whats-the-difference-between-declare-class-and-interface) + - [What does it mean for an interface to extend a class?](#what-does-it-mean-for-an-interface-to-extend-a-class) + - [Why am I getting "TypeError: [base class name] is not defined in `__extends`?](#why-am-i-getting-typeerror-base-class-name-is-not-defined-in-__extends) + - [Why am I getting "TypeError: Cannot read property 'prototype' of undefined" in `__extends`?](#why-am-i-getting-typeerror-cannot-read-property-prototype-of-undefined-in-__extends) + - [Why doesn't extending built-ins like `Error`, `Array`, and `Map` work?](#why-doesnt-extending-built-ins-like-error-array-and-map-work) + - [Generics](#generics) + - [Why is `A` assignable to `A` for `interface A { }`?](#why-is-astring-assignable-to-anumber-for-interface-at--) + - [Why doesn't type inference work on this interface: `interface Foo { }`?](#why-doesnt-type-inference-work-on-this-interface-interface-foot--) + - [Why can't I write `typeof T`, `new T`, or `instanceof T` in my generic function?](#why-cant-i-write-typeof-t-new-t-or-instanceof-t-in-my-generic-function) + - [Modules](#modules) + - [Why are imports being elided in my emit?](#why-are-imports-being-elided-in-my-emit) + - [Why don't namespaces merge across different module files?](#why-dont-namespaces-merge-across-different-module-files) + - [Enums](#enums) + - [What's the difference between `enum` and `const enum`s?](#whats-the-difference-between-enum-and-const-enums) + - [Type Guards](#type-guards) + - [Why doesn't `x instanceof Foo` narrow `x` to `Foo`?](#why-doesnt-x-instanceof-foo-narrow-x-to-foo) + - [Why doesn't `isFoo(x)` narrow `x` to `Foo` when `isFoo` is a type guard?](#why-doesnt-isfoox-narrow-x-to-foo-when-isfoo-is-a-type-guard) + - [Decorators](#decorators) + - [Decorators on function declarations](#decorators-on-function-declarations) + - [What's the difference between `@dec` and `@dec()`? Shouldn't they be equivalent?](#whats-the-difference-between-dec-and-dec-shouldnt-they-be-equivalent) + - [JSX and React](#jsx-and-react) + - [I wrote `declare var MyComponent: React.Component;`, why can't I write ``?](#i-wrote-declare-var-mycomponent-reactcomponent-why-cant-i-write-mycomponent-) + - [Things That Don't Work](#things-that-dont-work) + - [You should emit classes like this so they have real private members](#you-should-emit-classes-like-this-so-they-have-real-private-members) + - [You should emit classes like this so they don't lose `this` in callbacks](#you-should-emit-classes-like-this-so-they-dont-lose-this-in-callbacks) + - [You should have some class initialization which is impossible to emit code for](#you-should-have-some-class-initialization-which-is-impossible-to-emit-code-for) + - [External Tools](#external-tools) + - [How do I write unit tests with TypeScript?](#how-do-i-write-unit-tests-with-typescript) + - [Commandline Behavior](#commandline-behavior) + - [Why did adding an `import` or `export` modifier break my program?](#why-did-adding-an-import-or-export-modifier-break-my-program) + - [How do I control file ordering in combined output (`--out`)?](#how-do-i-control-file-ordering-in-combined-output---out) + - [What does the error "Exported variable [name] has or is using private name [name]" mean?](#what-does-the-error-exported-variable-name-has-or-is-using-private-name-name-mean) + - [Why does `--outDir` moves output after adding a new file?](#why-does---outdir-moves-output-after-adding-a-new-file) + - [`tsconfig.json` Behavior](#tsconfigjson-behavior) + - [Why is a file in the `exclude` list still picked up by the compiler?](#why-is-a-file-in-the-exclude-list-still-picked-up-by-the-compiler) + - [How can I specify an `include`?](#how-can-i-specify-an-include) + - [Why am I getting the `error TS5055: Cannot write file 'xxx.js' because it would overwrite input file.` when using JavaScript files?](#why-am-i-getting-the-error-ts5055-cannot-write-file-xxxjs-because-it-would-overwrite-input-file-when-using-javascript-files) + - [Comments](#comments) + - [Why some comments are not preserved in emitted JavaScript even when `--removeComments` is not specified?](#why-some-comments-are-not-preserved-in-emitted-javascript-even-when---removecomments-is-not-specified) + - [Why Copyright comments are removed when `--removeComments` is true?](#why-copyright-comments-are-removed-when---removecomments-is-true) +- [Glossary and Terms in this FAQ](#glossary-and-terms-in-this-faq) + - [Dogs, Cats, and Animals, Oh My](#dogs-cats-and-animals-oh-my) + - ["Substitutability"](#substitutability) + - [Trailing, leading, and detached comments](#trailing-leading-and-detached-comments) +- [GitHub Process Questions](#github-process-questions) + - [What do the labels on these issues mean?](#what-do-the-labels-on-these-issues-mean) + - [I disagree with the outcome of this suggestion](#i-disagree-with-the-outcome-of-this-suggestion) + + + +## Common "Bugs" That Aren't Bugs + +> I've found a long-overlooked bug in TypeScript! + +Here are some behaviors that may look like bugs, but aren't. + +* These two empty classes can be used in place of each other + * See the [FAQ Entry on this page](#why-do-these-empty-classes-behave-strangely) +* I can use a non-`void`-returning function where one returning `void` is expected + * See the [FAQ Entry on this page](#why-are-functions-returning-non-void-assignable-to-function-returning-void) + * Prior discussion at #4544 +* I'm allowed to use a shorter parameter list where a longer one is expected + * See the [FAQ Entry on this page](#why-are-functions-with-fewer-parameters-assignable-to-functions-that-take-more-parameters) + * Prior discussion at #370, #9300, #9765, #9825, #13043, #16871, #13529, #13977, #17868, #20274, #20541, #21868, #26324, #30876 +* `private` class members are actually visible at runtime + * See the [FAQ Entry on this page](#you-should-emit-classes-like-this-so-they-have-real-private-members) for a commonly suggested "fix" + * Prior discussion at #564, #1537, #2967, #3151, #6748, #8847, #9733, #11033 +* This conditional type returns `never` when it should return the true branch. + * See this [issue](https://github.com/microsoft/TypeScript/issues/31751) for discussion about _distributive conditional types_. +* This mapped type returns a primitive type, not an object type. + * Mapped types declared as `{ [ K in keyof T ]: U }` where T is a type parameter are known as _homomorphic mapped types_, which means that the mapped type is a structure preserving function of `T`. When type parameter `T` is instantiated with a primitive type the mapped type evaluates to the same primitive. +* A method and a function property of the same type behave differently. + * Methods are always bivariant in their argument, while function properties are contravariant in their argument under `strictFunctionTypes`. More discussion [here](https://github.com/microsoft/TypeScript/pull/18654). +* Export maps aren't respected. + * TypeScript's support for export maps is recent, and requires `moduleResolution` be set to `node16` or `nodenext` to be respected. +* A default import of a commonjs module with a default in a esm file doesn't seem to be the default export of that module when `module` is `node16` or `nodenext`. + * TypeScript is exposing `node`'s behavior here - when a esm module default imports a commonjs module, that whole commonjs module is made available as the default import. If you then want the actual default member of that module, you'll need to access the `default` member of that import. Refer to the [node documentation](https://nodejs.org/api/esm.html#commonjs-namespaces) for more information. + +## Common Feature Requests +> I want to request one of the following features... + +Here's a list of common feature requests and their corresponding issue. +Please leave comments in these rather than logging new issues. +* Safe navigation operator, AKA CoffeeScript's null conditional/propagating/propagation operator, AKA C#'s' `?.` operator [#16](https://github.com/Microsoft/TypeScript/issues/16) +* Minification [#8](https://github.com/Microsoft/TypeScript/issues/8) +* Extension methods [#9](https://github.com/Microsoft/TypeScript/issues/9) +* Partial classes [#563](https://github.com/Microsoft/TypeScript/issues/563) +* Something to do with `this` [#513](https://github.com/Microsoft/TypeScript/issues/513) +* Strong typing of `Function` members `call`/`bind`/`apply` [#212](https://github.com/Microsoft/TypeScript/issues/212) +* Runtime function overloading [#3442](https://github.com/Microsoft/TypeScript/issues/3442) + +## Type System Behavior + +### What is structural typing? +TypeScript uses *structural typing*. +This system is different than the type system employed by some other popular languages you may have used (e.g. Java, C#, etc.) + +The idea behind structural typing is that two types are compatible if their *members* are compatible. +For example, in C# or Java, two classes named `MyPoint` and `YourPoint`, both with public `int` properties `x` and `y`, are not interchangeable, even though they are identical. +But in a structural type system, the fact that these types have different names is immaterial. +Because they have the same members with the same types, they are identical. + +This applies to subtype relationships as well. +In C++, for example, you could only use a `Dog` in place of an `Animal` if `Animal` was explicitly in `Dog`'s class heritage. +In TypeScript, this is not the case - a `Dog` with at least as many members (with appropriate types) as `Animal` is a subtype of `Animal` regardless of explicit heritage. + +This can have some surprising consequences for programmers accustomed to working in a nominally-typed language. +Many questions in this FAQ trace their roots to structural typing and its implications. +Once you grasp the basics of it, however, it's very easy to reason about. + +### What is type erasure? + +TypeScript *removes* type annotations, interfaces, type aliases, and other type system constructs during compilation. + +Input: + +```ts +var x: SomeInterface; +``` + +Output: + +```js +var x; +``` + +This means that at run-time, there is no information present that says that some variable `x` was declared as being of type `SomeInterface`. + +The lack of run-time type information can be surprising for programmers who are used to extensively using reflection or other metadata systems. +Many questions in this FAQ boil down to "because types are erased". + +### Why are getters without setters not considered read-only? + +> I wrote some code like this and expected an error: +> ```ts +> class Foo { +> get bar() { +> return 42; +> } +> } +> let x = new Foo(); +> // Expected error here +> x.bar = 10; +> ``` + +This is now an error in TypeScript 2.0 and later. +See [#12](https://github.com/Microsoft/TypeScript/issues/12) for the suggestion tracking this issue. + +### Why are function parameters bivariant? + + > I wrote some code like this and expected an error: + > ```ts + > function trainDog(d: Dog) { ... } + > function cloneAnimal(source: Animal, done: (result: Animal) => void): void { ... } + > let c = new Cat(); + > + > // Runtime error here occurs because we end up invoking 'trainDog' with a 'Cat' + > cloneAnimal(c, trainDog); + > ``` + +This is an unsoundness resulting from the lack of explicit covariant/contravariant annotations in the type system. +Because of this omission, TypeScript must be more permissive when asked whether `(x: Dog) => void` is assignable to `(x: Animal) => void`. + +To understand why, consider two questions: Is `Dog[]` a subtype of `Animal[]`? *Should* `Dog[]` be a subtype of `Animal[]` in TypeScript? + +The second question (*should* `Dog[]` be a subtype of `Animal[]`?) is easier to analyze. +What if the answer was "no"? + +```ts +function checkIfAnimalsAreAwake(arr: Animal[]) { ... } + +let myPets: Dog[] = [spot, fido]; + +// Error? Can't substitute Dog[] for Animal[]? +checkIfAnimalsAreAwake(myPets); +``` + +This would be *incredibly annoying*. +The code here is 100% correct provided that `checkIfAnimalsAreAwake` doesn't modify the array. +There's not a good reason to reject this program on the basis that `Dog[]` can't be used in place of `Animal[]` - clearly a group of `Dog`s is a group of `Animal`s here. + +Back to the first question. +When the type system decides whether or not `Dog[]` is a subtype of `Animal[]`, it does the following computation (written here as if the compiler took no optimizations), among many others: + + * Is `Dog[]` assignable to `Animal[]`? + * Is each member of `Dog[]` assignable to `Animal[]`? + * Is `Dog[].push` assignable to `Animal[].push`? + * Is the type `(x: Dog) => number` assignable to `(x: Animal) => number`? + * Is the first parameter type in `(x: Dog) => number` assignable to or from first parameter type in `(x: Animal) => number`? + * Is `Dog` assignable to or from `Animal`? + * Yes. + +As you can see here, the type system must ask "Is the type `(x: Dog) => number` assignable to `(x: Animal) => number`?", +which is the same question the type system needed to ask for the original question. +If TypeScript forced contravariance on parameters (requiring `Animal` being assignable to `Dog`), then `Dog[]` would not be assignable to `Animal[]`. + +In summary, in the TypeScript type system, the question of whether a more-specific-type-accepting function should be assignable to a function accepting a less-specific type provides a prerequisite answer to whether an *array* of that more specific type should be assignable to an array of a less specific type. +Having the latter *not* be the case would not be an acceptable type system in the vast majority of cases, +so we have to take a correctness trade-off for the specific case of function argument types. + +### Why are functions with fewer parameters assignable to functions that take more parameters? + +> I wrote some code like this and expected an error: +> ```ts +> function handler(arg: string) { +> // .... +> } +> +> function doSomething(callback: (arg1: string, arg2: number) => void) { +> callback('hello', 42); +> } +> +> // Expected error because 'doSomething' wants a callback of +> // 2 parameters, but 'handler' only accepts 1 +> doSomething(handler); +> ``` + +This is the expected and desired behavior. +First, refer to the "substitutability" primer at the top of the FAQ -- `handler` is a valid argument for `callback` because it can safely ignore extra parameters. + +Second, let's consider another case: +```ts +let items = [1, 2, 3]; +items.forEach(arg => console.log(arg)); +``` + +This is isomorphic to the example that "wanted" an error. +At runtime, `forEach` invokes the given callback with three arguments (value, index, array), but most of the time the callback only uses one or two of the arguments. +This is a very common JavaScript pattern and it would be burdensome to have to explicitly declare unused parameters. + +> But `forEach` should just mark its parameters as optional! +> e.g. `forEach(callback: (element?: T, index?: number, array?: T[]))` + +This is *not* what an optional callback parameter means. +Function signatures are always read from the *caller's* perspective. +If `forEach` declared that its callback parameters were optional, the meaning of that is "`forEach` **might call the callback with 0 arguments**". + +The meaning of an optional callback parameter is *this*: +```ts +// Invoke the provided function with 0 or 1 argument +function maybeCallWithArg(callback: (x?: number) => void) { + if (Math.random() > 0.5) { + callback(); + } else { + callback(42); + } +} +``` +`forEach` *always* provides all three arguments to its callback. +You don't have to check for the `index` argument to be `undefined` - it's always there; it's not optional. + +There is currently not a way in TypeScript to indicate that a callback parameter *must* be present. +Note that this sort of enforcement wouldn't ever directly fix a bug. +In other words, in a hypothetical world where `forEach` callbacks were required to accept a minimum of one argument, you'd have this code: +```ts +[1, 2, 3].forEach(() => console.log("just counting")); + // ~~ Error, not enough arguments? +``` +which would be "fixed", but *not made any more correct*, by adding a parameter: +```ts +[1, 2, 3].forEach(x => console.log("just counting")); + // OK, but doesn't do anything different at all +``` + +### Why are functions returning non-`void` assignable to function returning `void`? + +> I wrote some code like this and expected an error: +> ```ts +> function doSomething(): number { +> return 42; +> } +> +> function callMeMaybe(callback: () => void) { +> callback(); +> } +> +> // Expected an error because 'doSomething' returns number, but 'callMeMaybe' +> // expects void-returning function +> callMeMaybe(doSomething); +> ``` + +This is the expected and desired behavior. +First, refer to the "substitutability" primer -- the fact that `doSomething` returns "more" information than `callMeMaybe` is a valid substitution. + +Second, let's consider another case: +```ts +let items = [1, 2]; +callMeMaybe(() => items.push(3)); +``` +This is isomorphic to the example that "wanted" an error. +`Array#push` returns a number (the new length of the array), but it's a safe substitute to use for a `void`-returning function. + +Another way to think of this is that a `void`-returning callback type says "I'm not going to look at your return value, if one exists". + +### Why are all types assignable to empty interfaces? + +> I wrote some code like this and expected an error: +> ```ts +> interface Thing { /* nothing here */ } +> function doSomething(a: Thing) { +> // mysterious implementation here +> } +> // Expected some or all of these to be errors +> doSomething(window); +> doSomething(42); +> doSomething('huh?'); +> ``` + +Types with no members can be substituted by *any* type. +In this example, `window`, `42`, and `'huh?'` all have the required members of a `Thing` (there are none). + +In general, you should *never* find yourself declaring an `interface` with no properties. + +### Can I make a type alias nominal? + +> I wrote the following code and expected an error: +> ```ts +> type SomeUrl = string; +> type FirstName = string; +> let x: SomeUrl = "http://www.typescriptlang.org/"; +> let y: FirstName = "Bob"; +> x = y; // Expected error +> ``` + +Type aliases are simply *aliases* -- they are indistinguishable from the types they refer to. + +A workaround involving intersection types to make "branded primitives" is possible: +```ts +// Strings here are arbitrary, but must be distinct +type SomeUrl = string & {'this is a url': {}}; +type FirstName = string & {'person name': {}}; + +// Add type assertions +let x = ''; +let y = 'bob'; +x = y; // Error + +// OK +let xs: string = x; +let ys: string = y; +xs = ys; +``` +You'll need to add a type assertion wherever a value of this type is created. +These can still be aliased by `string` and lose type safety. + +### How do I prevent two types from being structurally compatible? +> I would like the following code to produce an error: +> ```ts +> interface ScreenCoordinate { +> x: number; +> y: number; +> } +> interface PrintCoordinate { +> x: number; +> y: number; +> } +> function sendToPrinter(pt: PrintCoordinate) { +> // ... +> } +> function getCursorPos(): ScreenCoordinate { +> // Not a real implementation +> return { x: 0, y: 0 }; +> } +> // This should be an error +> sendToPrinter(getCursorPos()); +> ``` + +A possible fix if you really want two types to be incompatible is to add a 'brand' member: +```ts +interface ScreenCoordinate { + _screenCoordBrand: any; + x: number; + y: number; +} +interface PrintCoordinate { + _printCoordBrand: any; + x: number; + y: number; +} + +// Error +sendToPrinter(getCursorPos()); +``` + +Note that this will require a type assertion wherever 'branded' objects are created: +```ts +function getCursorPos(): ScreenCoordinate { + // Not a real implementation + return { x: 0, y: 0 }; +} +``` + +See also [#202](https://github.com/Microsoft/TypeScript/issues/202) for a suggestion tracking making this more intuitive. + +### How do I check at run-time if an object implements some interface? + +> I want to write some code like this: +> ```ts +> interface SomeInterface { +> name: string; +> length: number; +> } +> interface SomeOtherInterface { +> questions: string[]; +> } +> +> function f(x: SomeInterface|SomeOtherInterface) { +> // Can't use instanceof on interface, help? +> if (x instanceof SomeInterface) { +> // ... +> } +> } +> ``` + +TypeScript types are erased (https://en.wikipedia.org/wiki/Type_erasure) during compilation. +This means there is no built-in mechanism for performing runtime type checks. +It's up to you to decide how you want to distinguish objects. +A popular method is to check for properties on an object. +You can use user-defined type guards to accomplish this: + +```ts +function isSomeInterface(x: any): x is SomeInterface { + return typeof x.name === 'string' && typeof x.length === 'number'; + +function f(x: SomeInterface|SomeOtherInterface) { + if (isSomeInterface(x)) { + console.log(x.name); // Cool! + } +} +``` + +### Why doesn't this incorrect cast throw a runtime error? +> I wrote some code like this: +> ```ts +> let x: any = true; +> let y = x; // Expected: runtime error (can't convert boolean to string) +> ``` +or this +> ```ts +> let a: any = 'hmm'; +> let b = a as HTMLElement; // expected b === null +> ``` + +TypeScript has *type assertions*, not *type casts*. +The intent of `x` is to say "TypeScript, please treat `x` as a `T`", not to perform a type-safe run-time conversion. +Because types are erased, there is no direct equivalent of C#'s `expr as` type or `(type)expr` syntax. + + +### Why don't I get type checking for `(number) => string` or `(T) => T`? +> I wrote some code like this and expected an error: +> ```ts +> let myFunc: (number) => string = (n) => 'The number in hex is ' + n.toString(16); +> // Expected error because boolean is not number +> console.log(myFunc(true)); +> ``` + +Parameter names in function types are required. +The code as written describes a function taking one parameter named `number` of type `any`. +In other words, this declaration +```ts +let myFunc: (number) => string; +``` +is equivalent to this one +```ts +let myFunc: (number: any) => string; +``` + +You should instead write: +```ts +let myFunc: (myArgName: number) => string; +``` + +To avoid this problem, turn on the `noImplicitAny` flag, which will issue a warning about the implicit `any` parameter type. + +### Why am I getting an error about a missing index signature? + +> These three functions seem to do the same thing, but the last one is an error. Why is this the case? +> ```ts +> interface StringMap { +> [key: string]: string; +> } +> +> function a(): StringMap { +> return { a: "1" }; // OK +> } +> +> function b(): StringMap { +> var result: StringMap = { a: "1" }; +> return result; // OK +> } +> +> function c(): StringMap { +> var result = { a: "1" }; +> return result; // Error - result lacks index signature, why? +> } +> ``` + +This isn't now an error in TypeScript 1.8 and later. As for earlier versions: + +Contextual typing occurs when the context of an expression gives a hint about what its type might be. For example, in this initialization: + +```ts +var x: number = y; +``` + +The expression `y` gets a contextual type of `number` because it's initializing a value of that type. In this case, nothing special happens, but in other cases more interesting things will occur. + +One of the most useful cases is functions: + +```ts +// Error: string does not contain a function called 'ToUpper' +var x: (n: string) => void = (s) => console.log(s.ToUpper()); +``` + +How did the compiler know that `s` was a `string`? If you wrote that function expression by itself, `s` would be of type `any` and there wouldn't be any error issued. But because the function was contextually typed by the type of `x`, the parameter `s` acquired the type `string`. Very useful! + +At the same time, an index signature specifies the type when an object is indexed by a `string` or a `number`. Naturally, these signatures are part of type checking: + +```ts +var x: { [n: string]: Car; }; +var y: { [n: string]: Animal; }; +x = y; // Error: Cars are not Animals, this is invalid +``` + +The lack of an index signature is also important: + +```ts +var x: { [n: string]: Car; }; +var y: { name: Car; }; +x = y; // Error: y doesn't have an index signature that returns a Car +``` + +The problem with assuming that objects don't have index signatures is that you then have no way to initialize an object with an index signature: + +```ts +var c: Car; +// Error, or not? +var x: { [n: string]: Car } = { 'mine': c }; +``` + +The solution is that when an object literal is contextually typed by a type with an index signature, that index signature is added to the type of the object literal if it matches. For example: + +```ts +var c: Car; +var a: Animal; +// OK +var x: { [n: string]: Car } = { 'mine': c }; +// Not OK: Animal is not Car +var y: { [n: string]: Car } = { 'mine': a }; +``` + +Let's look at the original function: + +```ts +function c(): StringMap { + var result = { a: "1" }; + return result; // Error - result lacks index signature, why? +} +``` + +Because `result`'s type does not have an index signature, the compiler throws an error. + +### Why am I getting `Supplied parameters do not match any signature` error? + +A function or a method implementation signature is not part of the overloads. + +```ts +function createLog(message:string): number; +function createLog(source:string, message?:string): number { + return 0; +} + +createLog("message"); // OK +createLog("source", "message"); // ERROR: Supplied parameters do not match any signature +``` + +When having at least one overload signature declaration, only the overloads are visible. The last signature declaration, also known as the implementation signature, does not contribute to the shape of your signature. So to get the desired behavior you will need to add an additional overload: + +```ts +function createLog(message:string): number; +function createLog(source:string, message:string): number +function createLog(source:string, message?:string): number { + return 0; +} +``` + +The rationale here is that since JavaScript does not have function overloading, you will be doing parameter checking in your function, and this your function implementation might be more permissive than what you would want your users to call you through. + +For instance you can require your users to call you using matching pairs of arguments, and implement this correctly without having to allow mixed argument types: + +```ts +function compare(a: string, b: string): void; +function compare(a: number, b: number): void; +function compare(a: string|number, b: string|number): void { + // Just an implementation and not visible to callers +} + +compare(1,2) // OK +compare("s", "l") // OK +compare (1, "l") // Error. +``` + +------------------------------------------------------------------------------------- + +## Functions + +### Why can't I use `x` in the destructuring `function f({ x: number }) { /* ... */ }`? +> I wrote some code like this and got an unexpected error: +> ```ts +> function f({x: number}) { +> // Error, x is not defined? +> console.log(x); +> } +> ``` + +Destructuring syntax is counterintuitive for those accustomed to looking at TypeScript type literals. +The syntax `f({x: number})` declares a destructuring *from the property* `x` *to the local* `number`. + +Looking at the emitted code for this is instructive: +```ts +function f(_a) { + // Not really what we were going for + var number = _a.x; +} +``` + +To write this code correctly, you should write: +```ts +function f({x}: {x: number}) { + // OK + console.log(x); +} +``` + +If you can provide a default for all properties, it's preferable to write: +```ts +function f({x = 0}) { + // x: number + console.log(x); +} +``` + +------------------------------------------------------------------------------------- + +## Classes + +### Why do these empty classes behave strangely? + +> I wrote some code like this and expected an error: +> ```ts +> class Empty { /* empty */ } +> +> var e2: Empty = window; +> ``` + +See the question ["Why are all types assignable to empty interfaces?"](#why-are-all-types-assignable-to-empty-interfaces) in this FAQ. +It's worth re-iterating the advice from that answer: in general, you should *never* declare a `class` with no properties. +This is true even for subclasses: + +```ts +class Base { + important: number; + properties: number; +} +class Alpha extends Base { } +class Bravo extends Base { } +``` + +`Alpha` and `Bravo` are structurally identical to each other, and to `Base`. +This has a lot of surprising effects, so don't do it! +If you want `Alpha` and `Bravo` to be different, add a private property to each. + +### When and why are classes nominal? + +What explains the difference between these two lines of code? +```ts +class Alpha { x: number } +class Bravo { x: number } +class Charlie { private x: number } +class Delta { private x: number } + +let a = new Alpha(), b = new Bravo(), c = new Charlie(), d = new Delta(); + +a = b; // OK +c = d; // Error +``` + +In TypeScript, classes are compared structurally. +The one exception to this is `private` and `protected` members. +When a member is private or protected, it must *originate in the same declaration* to be considered the same as another private or protected member. + + +### Why does `this` get orphaned in my instance methods? + +> I wrote some code like this: +> ```ts +> class MyClass { +> x = 10; +> someCallback() { +> console.log(this.x); // Prints 'undefined', not 10 +> this.someMethod(); // Throws error "this.method is not a function" +> } +> someMethod() { +> +> } +> } +> +> let obj = new MyClass(); +> window.setTimeout(obj.someCallback, 10); +> ``` + +Synonyms and alternate symptoms: +> * Why are my class properties `undefined` in my callback? +> * Why does `this` point to `window` in my callback? +> * Why does `this` point to `undefined` in my callback? +> * Why am I getting an error `this.someMethod is not a function`? +> * Why am I getting an error `Cannot read property 'someMethod' of undefined`? + +In JavaScript, the value of `this` inside a function is determined as follows: + 1. Was the function the result of calling `.bind`? If so, `this` is the first argument passed to `bind` + 2. Was the function *directly* invoked via a property access expression `expr.method()`? If so, `this` is `expr` + 3. Otherwise, `this` is `undefined` (in "strict" mode), or `window` in non-strict mode + +The offending problem is this line of code: +```ts +window.setTimeout(obj.someCallback, 10); +``` +Here, we provided a function reference to `obj.someCallback` to `setTimeout`. +The function was then invoked on something that wasn't the result of `bind` and wasn't *directly* invoked as a method. +Thus, `this` in the body of `someCallback` referred to `window` (or `undefined` in strict mode). + +Solutions to this are outlined here: http://stackoverflow.com/a/20627988/1704166 + +### What's the difference between `Bar` and `typeof Bar` when `Bar` is a `class`? +> I wrote some code like this and don't understand the error I'm getting: +> ```ts +> class MyClass { +> someMethod() { } +> } +> var x: MyClass; +> // Cannot assign 'typeof MyClass' to MyClass? Huh? +> x = MyClass; +> ``` + +It's important to remember that in JavaScript, classes are just functions. +We refer to the class object itself -- the *value* `MyClass` -- as a *constructor function*. +When a constructor function is invoked with `new`, we get back an object that is an *instance* of the class. + +So when we define a class, we actually define two different *types*. + +The first is the one referred to by the class' name; in this case, `MyClass`. +This is the *instance* type of the class. +It defines the properties and methods that an *instance* of the class has. +It's the type returned by invoking the class' constructor. + +The second type is anonymous. +It is the type that the constructor function has. +It contains a *construct signature* (the ability to be invoked with `new`) that returns an *instance* of the class. +It also contains any `static` properties and methods the class might have. +This type is typically referred to as the "static side" of the class because it contains those static members (as well as being the *constructor* for the class). +We can refer to this type with the type query operator `typeof`. + +The `typeof` operator (when used in a *type* position) expresses the *type* of an *expression*. +Thus, `typeof MyClass` refers to the type of the expression `MyClass` - the *constructor function* that produces instances of `MyClass`. + + +### Why do my derived class property initializers overwrite values set in the base class constructor? +See [#1617](https://github.com/Microsoft/TypeScript/issues/1617) for this and other initialization order questions + + +### What's the difference between `declare class` and `interface`? + +TODO: Write up common symptoms of `declare class` / `interface` confusion. + +See http://stackoverflow.com/a/14348084/1704166 + + +### What does it mean for an interface to extend a class? + +> What does this code mean? +> +> ```ts +> class Foo { +> /* ... */ +> } +> interface Bar extends Foo { +> +> } +> ``` + +This makes a type called `Bar` that has the same members as the instance shape of `Foo`. +However, if `Foo` has private members, their corresponding properties in `Bar` must be implemented +by a class which has `Foo` in its heritage. +In general, this pattern is best avoided, especially if `Foo` has private members. + +### Why am I getting "TypeError: [base class name] is not defined in `__extends`? +> I wrote some code like this: +> ```ts +> /** file1.ts **/ +> class Alpha { /* ... */ } +> +> /** file2.ts **/ +> class Bravo extends Alpha { /* ... */ } +> ``` +> I'm seeing a runtime error in `__extends`: +> ``` +> Uncaught TypeError: Alpha is not defined +> ``` + +The most common cause of this is that your HTML page includes a `