diff --git a/'this'-in-TypeScript.md b/'this'-in-TypeScript.md index b9b1575d..53fbb895 100644 --- a/'this'-in-TypeScript.md +++ b/'this'-in-TypeScript.md @@ -104,12 +104,32 @@ someCallback((n, m) => x.doSomething(n, m)); ### Function.bind ```ts var x = new SomeClass(); -// SAFE: Functions created from function.bind are always preserve 'this' +// 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, if that matters + * 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/.github/workflows/sync b/.github/workflows/sync new file mode 100755 index 00000000..c33be1bc --- /dev/null +++ b/.github/workflows/sync @@ -0,0 +1,49 @@ +#!/usr/bin/env bash + +# This script implements a two-way mirroring bewteen a GH wiki for a repo `R` +# (called `DOTREMOTE` below) with a public repo `R-wiki` (intended for external +# contributions, called `DASHREMOTE` below). See `sync.yml` for how it is +# triggered: it is a minimal-ish yaml file that should be added to both sides +# (`R` and `R-wiki`), with a `push` trigger on `R-wiki` (and optionally a +# schedule) and a `gollum` trigger on `R`. The action spec is careful to +# always checkout `R-wiki` (`DASHREMOTE`) since checking out `R` would be +# useless. It then merges in changes in `DOTREMOTE` and pushes the results to +# both. Pushing the merged version will trigger an action on the other side, +# but that would be very quick (both the `merge` and pushing it will be +# no-ops.) + +set -ue +shopt -s extglob + +PUSHER="${PUSHER// +( )/ }"; PUSHER="${PUSHER# }"; PUSHER="${PUSHER% }" +NAME="${PUSHER% <*}" +EMAIL="${PUSHER##* <}"; EMAIL="${EMAIL%>}" +echo "Setting git username to \"$NAME\" and email to \"$EMAIL\"" +export GIT_AUTHOR_NAME="$NAME" +export GIT_AUTHOR_EMAIL="$EMAIL" +export GIT_COMMITTER_NAME="$NAME" +export GIT_COMMITTER_EMAIL="$EMAIL" + +DASHREMOTE="$(git remote get-url origin)" +DOTREMOTE="${DASHREMOTE//-wiki/.wiki}" +echo "DASHREMOTE = $DASHREMOTE, DOTREMOTE = $DOTREMOTE" + +for r in "$DASHREMOTE" "$DOTREMOTE"; do + if [[ "$(git ls-remote --symref "$r" HEAD | grep "^ref:")" \ + != $'ref: refs/heads/master\tHEAD' ]]; then + echo "Unexpected branch name at $r: expected to see \"master\"" + fi +done + +echo ">>> Adding and fetching DOTREMOTE" +git remote add dot "$DOTREMOTE" +git fetch dot + +echo ">>> Merging changes" +git pull --no-edit --no-rebase dot "master" + +echo ">>> Pushing merges to DASHREMOTE" +git push origin + +echo ">>> Pushing merges to DOTREMOTE" +git push dot main:master diff --git a/.github/workflows/sync.yml b/.github/workflows/sync.yml new file mode 100644 index 00000000..8a8e7fec --- /dev/null +++ b/.github/workflows/sync.yml @@ -0,0 +1,27 @@ +# Roughly based on +# https://www.growingwiththeweb.com/2016/07/enabling-pull-requests-on-github-wikis.html + +name: Sync Two Wiki Repos + +on: + push: {branches: [main]} + schedule: [{cron: "7 0 * * 1,3"}] # https://crontab.guru/#7_0_*_*_1,3 + workflow_dispatch: # on request + +jobs: + sync: + runs-on: ubuntu-latest + steps: + - name: Get repo name + run: R=${GITHUB_REPOSITORY%?wiki}; echo "BASENAME=${R##*/}" >> $GITHUB_ENV + - name: Checkout ${{ env.BASENAME }}-wiki + uses: actions/checkout@v4 + with: + repository: "${{ GITHUB.repository_owner }}/${{ env.BASENAME }}-wiki" + token: ${{ secrets.TS_BOT_TOKEN }} + fetch-depth: 0 + - name: Run sync + run: ./.github/workflows/sync + env: + PUSHER: typescript-bot + AUTH: ${{ secrets.TS_BOT_TOKEN }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..8ed982c1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +yarn.lock +node_modules/ +package-lock.json +TypeScript diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..cfa79fa8 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,7 @@ +{ + "[markdown]": { + "editor.rulers": [ + 80 + ], + } +} diff --git a/API-Breaking-Changes.md b/API-Breaking-Changes.md index 20d50624..fc2cb530 100644 --- a/API-Breaking-Changes.md +++ b/API-Breaking-Changes.md @@ -1,3 +1,259 @@ +# 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 @@ -40,6 +296,6 @@ We did some cleanup to the public interfaces, here is the full list of changes: ### `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-per-case basis. +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). \ No newline at end of file +For more information please see the [full change](https://github.com/Microsoft/TypeScript/pull/2692). diff --git a/All-The-Bots.md b/All-The-Bots.md new file mode 100644 index 00000000..f748562c --- /dev/null +++ b/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 +- https://github.com/microsoft/typescript-benchmarking -- produces PR comments showing benchmark results + +## 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 the publisher on GitHub Actions +- [DangerBotOSS](https://github.com/definitelytyped/definitelytyped/tree/main/.github/workflows/CI.yml) -- suggests missed exports (posts as DangerBotOSS, not typescript-bot) diff --git a/Arcane-Details-of-the-Compiler.md b/Arcane-Details-of-the-Compiler.md deleted file mode 100644 index a1bad211..00000000 --- a/Arcane-Details-of-the-Compiler.md +++ /dev/null @@ -1,25 +0,0 @@ -This is an incomplete page that will need to be updated as time goes on. The intent is that there are gaps of knowledge that are understood well among the team (or even just specific team members) which would be better if understood across a broader audience. - -# Parser - -## Incremental parsing - -## ECMAScript parsing contexts - -## ECMAScript automatic semicolon insertion - -# Checker - -## Grammatical checking - -## Overload resolution - -## Type argument inference - -### Type argument fixing - -# Emitter - -## Rewriting & synthesized nodes - -## Sourcemap generation \ No newline at end of file diff --git a/Architectural-Overview.md b/Architectural-Overview.md index dafc2c35..f208cdbe 100644 --- a/Architectural-Overview.md +++ b/Architectural-Overview.md @@ -1,104 +1,15 @@ ## Layer Overview - -![Architectural overview.](https://raw.githubusercontent.com/wiki/Microsoft/TypeScript/images/architecture.png) - -* **Core TypeScript Compiler** - * **Parser:** Starting from a set of sources, and following the productions of the language grammar, to generate an Abstract Syntax Tree (AST) - - * **Binder:** Linking declarations contributing to the same structure using a Symbol (e.g. different declarations of the same interface or module, or a function and a module with the same name). This allows the type system to reason about these named declarations. - - * **Type resolver/ Checker:** Resolving types of each construct, checking semantic operations and generate diagnostics as appropriate. - - * **Emitter:** Output generated from a set of inputs (.ts and .d.ts) files can be one of: JavaScript (.js), definitions (.d.ts), or source maps (.js.map) - - * **Pre-processor:** The "Compilation Context" refers to all files involved in a "program". The context is created by inspecting all files passed in to the compiler on the command line, in order, and then adding any files they may reference directory or indirectly through "import" statements and /// tags. -The result of walking the reference graph is an ordered list of source files, that constitute the program. -When resolving imports, preference is given to ".ts" files over ".d.ts" files to ensure the most up-to-date files are processed. -The compiler does a node-like process to resolve imports by walking up the directory chain to find a source file with a .ts or .d.ts extension matching the requested import. -Failed import resolution does not result in an error, as an ambient module could be already declared. - -* **Standalone compiler (tsc):** The batch compilation CLI. Mainly handle reading and writing files for different supported engines (e.g. node js) - -* **Language Service:** The "Language Service" exposes an additional layer around the core compiler pipeline that are best suiting editor-like applications. -The language service supports the common set of a typical editor operations like statement completions, signature help, code formatting and outlining, colorization, etc... Basic re-factoring like rename, Debugging interface helpers like validating breakpoints as well as TypeScript-specific features like support of incremental compilation (--watch equivalent on the command-line). The language service is designed to efficiently handle scenarios with files changing over time within a long-lived compilation context; in that sense, the language service provides a slightly different perspective about working with programs and source files from that of the other compiler interfaces. -> Please refer to the [[Using the Language Service API]] page for more details. - ## Data Structures -* **Node:** The basic building block of the Abstract Syntax Tree (AST). In general node represent non-terminals in the language grammar; some terminals are kept in the tree such as identifiers and literals. - -* **SourceFile:** The AST of a given source file. A SourceFile is itself a Node; it provides an additional set of interfaces to access the raw text of the file, references in the file, the list of identifiers in the file, and mapping from a position in the file to a line and character numbers. - -* **Program:** A collection of SourceFiles and a set of compilation options that represent a compilation unit. The program is the main entry point to the type system and code generation. - -* **Symbol:** A named declaration. Symbols are created as a result of binding. Symbols connect declarations nodes in the tree to other declarations contributing to the same entity. Symbols are the basic building block of the semantic system. +Moved to [the glossary](https://github.com/microsoft/TypeScript-Compiler-Notes/blob/main/GLOSSARY.md) of the compiler-notes repo. -* **Type:** Types is the other part of the semantic system. Types can be named (e.g. classes and interfaces), or anonymous (e.g. object types). +## Overview of the compilation process -* **Signature:** There are three types of signatures in the language, call, construct and index signatures. +Moved to the root readme of the [compiler-notes repo](https://github.com/microsoft/TypeScript-Compiler-Notes). ## Terminology -##### **Full Start/Token Start** - -Tokens themselves have what we call a "full start" and a "token start". The "token start" is the more natural version, which is the position in file where the text of a token begins. The "full start" is the point at which the scanner began scanning since the last significant token. When concerned with trivia, we are often more concerned with the full start. - -Function | Description ----------|------------ -`ts.Node.getStart` | Gets the position in text where the first token of a node started. -`ts.Node.getFullStart` | Gets the position of the "full start" of the first token owned by the node. - -#### **Trivia** - -Syntax trivia represent the parts of the source text that are largely insignificant for normal understanding of the code, such as whitespace, comments, and even conflict markers. - -Because trivia are not part of the normal language syntax (barring ECMAScript ASI rules) and can appear anywhere between any two tokens, they are not included in the syntax tree. Yet, because they are important when implementing a feature like refactoring and to maintain full fidelity with the source text, they are still accessible through our APIs on demand. - -Because the `EndOfFileToken` can have nothing following it (neither token nor trivia), all trivia naturally precedes some non-trivia token, and resides between that token's "full start" and the "token start" - -It is a convenient notion to state that a comment "belongs" to a `Node` in a more natural manner though. For instance, it might be visually clear that the `genie` function declaration owns the last two comments in the following example: - -```TypeScript -var x = 10; // This is x. - -/** - * Postcondition: Grants all three wishes. - */ -function genie([wish1, wish2, wish3]: [Wish, Wish, Wish]) { - while (true) { - } -} // End function -``` - -This is despite the fact that the function declaration's full start occurs directly after `var x = 10;`. - -We follow [Roslyn's notion of trivia ownership](https://github.com/dotnet/roslyn/wiki/Roslyn%20Overview#syntax-trivia) for comment ownership. In general, a token owns any trivia after it on the same line up to the next token. Any comment after that line is associated with the following token. The first token in the source file gets all the initial trivia, and the last sequence of trivia in the file is tacked onto the end-of-file token, which otherwise has zero width. - -For most basic uses, comments are the "interesting" trivia. The comments that belong to a Node which can be fetched through the following functions: - -Function | Description ----------|------------ -`ts.getLeadingCommentRanges` | Given the source text and position within that text, returns ranges of comments between the first line break following the given position and the token itself (probably most useful with `ts.Node.getFullStart`). -`ts.getTrailingCommentRanges` | Given the source text and position within that text, returns ranges of comments until the first line break following the given position (probably most useful with `ts.Node.getEnd`). - -As an example, imagine this portion of a source file: - -```TypeScript -debugger;/*hello*/ - //bye - /*hi*/ function -``` - -The full start for the `function` keyword begins at the `/*hello*/` comment, but `getLeadingCommentRanges` will only return the last 2 comments: - -``` -d e b u g g e r ; / * h e l l o * / _ _ _ _ _ [CR] [NL] _ _ _ _ / / b y e [CR] [NL] _ _ / * h i * / _ _ _ _ f u n c t i o n - ↑ ↑ ↑ ↑ ↑ - full start look for first comment second comment token start - leading comments - starting here -``` - -Appropriately, calling `getTrailingCommentRanges` on the end of the debugger statement will extract the `/*hello*/` comment. +### **Full Start/Token Start** +### **Trivia** -In the event that you are concerned with richer information of the token stream, `createScanner` also has a `skipTrivia` flag which you can set to `false`, and use `setText`/`setTextPos` to scan at different points in a file. \ No newline at end of file +See [the Scanner](https://github.com/microsoft/TypeScript-Compiler-Notes/blob/main/codebase/src/compiler/scanner.md) in the compiler-notes repo. \ No newline at end of file diff --git a/Basic-Types.md b/Basic-Types.md deleted file mode 100644 index 26fa1f43..00000000 --- a/Basic-Types.md +++ /dev/null @@ -1,104 +0,0 @@ -# Introduction - -For programs to be useful, we need to be able to work with some of the simplest units of data: numbers, strings, structures, boolean values, and the like. In TypeScript, we support much the same types as you would expected in JavaScript, with a convenient enumeration type thrown in to help things along. - -# Boolean - -The most basic datatype is the simple true/false value, which JavaScript and TypeScript (as well as other languages) call a 'boolean' value. - -```TypeScript -var isDone: boolean = false; -``` - -# Number - -As in JavaScript, all numbers in TypeScript are floating point values. These floating point numbers get the type 'number'. - -```TypeScript -var height: number = 6; -``` - -# String - -Another fundamental part of creating programs in JavaScript for webpages and servers alike is working with textual data. As in other languages, we use the type 'string' to refer to these textual datatypes. Just like JavaScript, TypeScript also uses the double quote (") or single quote (') to surround string data. - -```TypeScript -var name: string = "bob"; -name = 'smith'; -``` - -# Array - -TypeScript, like JavaScript, allows you to work with arrays of values. Array types can be written in one of two ways. In the first, you use the type of the elements followed by '[]' to denote an array of that element type: - -```TypeScript -var list:number[] = [1, 2, 3]; -``` - -The second way uses a generic array type, Array: - -```TypeScript -var list:Array = [1, 2, 3]; -``` - -# Enum - -A helpful addition to the standard set of datatypes from JavaScript is the 'enum'. Like languages like C#, an enum is a way of giving more friendly names to sets of numeric values. - -```TypeScript -enum Color {Red, Green, Blue} -var c: Color = Color.Green; -``` - -By default, enums begin numbering their members starting at 0. You can change this by manually setting the value of one its members. For example, we can start the previous example at 1 instead of 0: - -```TypeScript -enum Color {Red = 1, Green, Blue} -var c: Color = Color.Green; -``` - -Or, even manually set all the values in the enum: - -```TypeScript -enum Color {Red = 1, Green = 2, Blue = 4} -var c: Color = Color.Green; -``` - -A handy feature of enums is that you can also go from a numeric value to the name of that value in the enum. For example, if we had the value 2 but weren't sure which that mapped to in the Color enum above, we could look up the corresponding name: - -```TypeScript -enum Color {Red = 1, Green, Blue} -var colorName: string = Color[2]; - -alert(colorName); -``` - -# Any - -We may need to describe the type of variables that we may not know when we are writing the application. These values may come from dynamic content, eg from the user or 3rd party library. In these cases, we want to opt-out of type-checking and let the values pass through compile-time checks. To do so, we label these with the 'any' type: - -```TypeScript -var notSure: any = 4; -notSure = "maybe a string instead"; -notSure = false; // okay, definitely a boolean -``` - -The 'any' type is a powerful way to work with existing JavaScript, allowing you to gradually opt-in and opt-out of type-checking during compilation. - -The 'any' type is also handy if you know some part of the type, but perhaps not all of it. For example, you may have an array but the array has a mix of different types: - -```TypeScript -var list:any[] = [1, true, "free"]; - -list[1] = 100; -``` - -# Void - -Perhaps the opposite in some ways to 'any' is 'void', the absence of having any type at all. You may commonly see this as the return type of functions that do not return a value: - -```TypeScript -function warnUser(): void { - alert("This is my warning message"); -} -``` diff --git a/Breaking-Changes.md b/Breaking-Changes.md index 27cde053..81b16942 100644 --- a/Breaking-Changes.md +++ b/Breaking-Changes.md @@ -2,28 +2,2819 @@ These changes list where implementation differs between versions as the spec and > For breaking changes to the compiler/services API, please check the [[API Breaking Changes]] page. -# TypeScript 1.6 +# 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/35967). + +## 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: -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). +* 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** -#### .js content of npm package is moved from 'bin' to 'lib' folder +As a recommendation, you can manually adjust the prototype immediately after any `super(...)` calls. -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). +```ts +class FooError extends Error { + constructor(m: string) { + super(m); + + // Set the prototype explicitly. + Object.setPrototypeOf(this, FooError.prototype); + } + + sayHello() { + return "hello " + this.message; + } +} +``` -#### Module body is parsed in strict mode +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). -In accordance with [the ES6 spec](http://people.mozilla.org/~jorendorff/es6-draft.html#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.. +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. -#### System module output uses bulk exports +## Literal types are inferred by default for `const` variables and `readonly` properties -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. +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 `!==`. -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. +**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. -#### Strict object literal assignment checking +**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 @@ -36,27 +2827,79 @@ y = { foo: 1, baz: 2 }; // Error, excess or misspelled property `baz` **Recommendations:** -To avoid the error, either define a indexer on the target type or use type assertion on the object literal in question. +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 +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 Bar extends Foo { +interface FooBar { + foo: number; bar: number; } var y: Foo; -y = { foo: 1, bar: 2 }; +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; +} ``` -#### Function and class default export declarations can no longer merge with entities intersecting in their meaning +`./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, +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() { @@ -109,24 +2952,52 @@ 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. +## 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. + return () => arguments; // Error: The 'arguments' object cannot be referenced in an arrow function. } ``` **Recommendations:** ```ts -// 1. Use named rest args +// 1. Use named rest args function f() { return (...args) => { args; } } @@ -137,8 +3008,8 @@ function f() { } ``` -#### 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 initalized with a literal or an expression. Starting with Typescript 1.5 all non-const enum members are not inlined. +## 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 @@ -155,13 +3026,13 @@ Add the `const` modifier to the enum declaration to ensure it is consistently in For more details see issue [#2183](https://github.com/Microsoft/TypeScript/issues/2183). -#### Contextual type flows through `super` and parenthesized expressions +## 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; +var x: SomeType = (n) => ((m) => q); +var y: SomeType = t ? (m => m.length) : undefined; class C extends CBase { constructor() { @@ -174,8 +3045,8 @@ class C extends CBase { 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. +## 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:** @@ -219,9 +3090,9 @@ You can keep using older versions of the library with newer version of the compi For more details, please see the [full change](https://github.com/Microsoft/TypeScript/pull/2739). -#### Class body is parsed in strict mode +## Class bodies are parsed in strict mode -In accordance with [the ES6 spec](http://people.mozilla.org/~jorendorff/es6-draft.html#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.. +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 @@ -229,7 +3100,7 @@ For full list of breaking changes see the [breaking change issues](https://githu 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 +## 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 @@ -238,7 +3109,7 @@ var b: { x: number; z?: number }; // was { x: number; z?: number; }[] // now { x: number; y?: number; }[] -var bs = [b, a]; +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```). @@ -249,7 +3120,7 @@ Provide a type annotation if you need a specific type to be chosen var bs: { x: number; y?: number; z?: number }[] = [b, a]; ``` -#### Generic Type Inference +## Generic Type Inference Using different types for multiple arguments of type T is now an error, even with constraints involved: ```ts @@ -284,7 +3155,7 @@ declare function foo(x: T, y:U): T|U; function f(x: T, y: U): T|U { return undefined; } ``` -#### Generic Rest Parameters +## Generic Rest Parameters You cannot use heterogeneous argument types anymore: ```ts @@ -294,14 +3165,14 @@ var r = makeArray(1, ""); // used to return {}[], now an error Likewise for `new Array(...)` **Recommendations** -Declare a back-compat signature if the 1.0 behavior was desired: +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 +## Overload Resolution with Type Argument Inference ```ts var f10: (x: T, b: () => (a: T) => void, y: T) => T; @@ -314,9 +3185,9 @@ Manually specify a type parameter 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. +## 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: @@ -326,7 +3197,7 @@ 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. @@ -338,7 +3209,7 @@ For full list of breaking changes see the [breaking change issues](https://githu ## Working with null and undefined in ways that are observably incorrect is now an error -Examples: +Examples: ```TypeScript var ResultIsNumber17 = +(null + undefined); @@ -359,4 +3230,6 @@ Examples: null.toBAZ(); undefined.toBAZ(); -``` \ No newline at end of file +``` + +
\ No newline at end of file diff --git a/Cancellation-Support-in-tsserver.md b/Cancellation-Support-in-tsserver.md new file mode 100644 index 00000000..8ffd8941 --- /dev/null +++ b/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/Classes.md b/Classes.md deleted file mode 100644 index 281ce87a..00000000 --- a/Classes.md +++ /dev/null @@ -1,300 +0,0 @@ -# Introduction - -Traditional JavaScript focuses on functions and prototype-based inheritance as the basic means of building up reusable components, but this may feel a bit awkward to programmers more comfortable with an object-oriented approach, where classes inherit functionality and objects are built from these classes. Starting with ECMAScript 6, the next version of JavaScript, JavaScript programmers will be able to build their applications using this object-oriented class-based approach. In TypeScript, we allow developers to use these techniques now, and compile them down to JavaScript that works across all major browsers and platforms, without having to wait for the next version of JavaScript. - -# Classes - -Let's take a look at a simple class-based example: - -```TypeScript -class Greeter { - greeting: string; - constructor(message: string) { - this.greeting = message; - } - greet() { - return "Hello, " + this.greeting; - } -} - -var greeter = new Greeter("world"); -``` - -The syntax should look very familiar if you've used C# or Java before. We declare a new class 'Greeter'. This class has three members, a property called 'greeting', a constructor, and a method 'greet'. - -You'll notice that in the class when we refer to one of the members of the class we prepend 'this.'. This denotes that it's a member access. - -In the last line we construct an instance of the Greeter class using 'new'. This calls into the constructor we defined earlier, creating a new object with the Greeter shape, and running the constructor to initialize it. - -# Inheritance - -In TypeScript, we can use common object-oriented patterns. Of course, one of the most fundamental pattern in class-based programming is being able to extend existing classes to create new ones using inheritance. - -Let's take a look at an example: - -```TypeScript -class Animal { - name:string; - constructor(theName: string) { this.name = theName; } - move(meters: number) { - alert(this.name + " moved " + meters + "m."); - } -} - -class Snake extends Animal { - constructor(name: string) { super(name); } - move() { - alert("Slithering..."); - super.move(5); - } -} - -class Horse extends Animal { - constructor(name: string) { super(name); } - move() { - alert("Galloping..."); - super.move(45); - } -} - -var sam = new Snake("Sammy the Python"); -var tom: Animal = new Horse("Tommy the Palomino"); - -sam.move(); -tom.move(34); -``` - -This example covers quite a bit of the inheritance features in TypeScript that are common to other languages. Here we see using the 'extends' keywords to create a subclass. You can see this where 'Horse' and 'Snake' subclass the base class 'Animal' and gain access to its features. - -The example also shows off being able to override methods in the base class with methods that are specialized for the subclass. Here both 'Snake' and 'Horse' create a 'move' method that overrides the 'move' from 'Animal', giving it functionality specific to each class. - -# Private/Public modifiers - -## Public by default -You may have noticed in the above examples we haven't had to use the word 'public' to make any of the members of the class visible. Languages like C# require that each member be explicitly labelled 'public' to be visible. In TypeScript, each member is public by default. - -You may still mark members a private, so you control what is publicly visible outside of your class. We could have written the 'Animal' class from the previous section like so: - -```TypeScript -class Animal { - private name:string; - constructor(theName: string) { this.name = theName; } - move(meters: number) { - alert(this.name + " moved " + meters + "m."); - } -} -``` - -## Understanding private - -TypeScript is a structural type system. When we compare two different types, regardless of where they came from, if the types of each member are compatible, then we say the types themselves are compatible. - -When comparing types that have 'private' members, we treat these differently. For two types to be considered compatible, if one of them has a private member, then the other must have a private member that originated in the same declaration. - -Let's look at an example to better see how this plays out in practice: - -```TypeScript -class Animal { - private name:string; - constructor(theName: string) { this.name = theName; } -} - -class Rhino extends Animal { - constructor() { super("Rhino"); } -} - -class Employee { - private name:string; - constructor(theName: string) { this.name = theName; } -} - -var animal = new Animal("Goat"); -var rhino = new Rhino(); -var employee = new Employee("Bob"); - -animal = rhino; -animal = employee; //error: Animal and Employee are not compatible -``` - -In this example, we have an 'Animal' and a 'Rhino', with 'Rhino' being a subclass of 'Animal'. We also have a new class 'Employee' that looks identical to 'Animal' in terms of shape. We create some instances of these classes and then try to assign them to each other to see what will happen. Because 'Animal' and 'Rhino' share the private side of their shape from the same declaration of 'private name: string' in 'Animal', they are compatible. However, this is not the case for 'Employee'. When we try to assign from an 'Employee' to 'Animal' we get an error that these types are not compatible. Even though 'Employee' also has a private member called 'name', it is not the same one as the one created in 'Animal'. - -## Parameter properties - -The keywords 'public' and 'private' also give you a shorthand for creating and initializing members of your class, by creating parameter properties. The properties let you can create and initialize a member in one step. Here's a further revision of the previous example. Notice how we drop 'theName' altogether and just use the shortened 'private name: string' parameter on the constructor to create and initialize the 'name' member. - -```TypeScript -class Animal { - constructor(private name: string) { } - move(meters: number) { - alert(this.name + " moved " + meters + "m."); - } -} -``` - -Using 'private' in this way creates and initializes a private member, and similarly for 'public'. - -# Accessors - -TypeScript supports getters/setters as a way of intercepting accesses to a member of an object. This gives you a way of having finer-grained control over how a member is accessed on each object. - -Let's convert a simple class to use 'get' and 'set'. First, let's start with an example without getters and setters. - -```TypeScript -class Employee { - fullName: string; -} - -var employee = new Employee(); -employee.fullName = "Bob Smith"; -if (employee.fullName) { - alert(employee.fullName); -} -``` - -While allowing people to randomly set fullName directly is pretty handy, this might get us in trouble if we people can change names on a whim. - -In this version, we check to make sure the user has a secret passcode available before we allow them to modify the employee. We do this by replacing the direct access to fullName with a 'set' that will check the passcode. We add a corresponding 'get' to allow the previous example to continue to work seamlessly. - -```TypeScript -var passcode = "secret passcode"; - -class Employee { - private _fullName: string; - - get fullName(): string { - return this._fullName; - } - - set fullName(newName: string) { - if (passcode && passcode == "secret passcode") { - this._fullName = newName; - } - else { - alert("Error: Unauthorized update of employee!"); - } - } -} - -var employee = new Employee(); -employee.fullName = "Bob Smith"; -if (employee.fullName) { - alert(employee.fullName); -} -``` - -To prove to ourselves that our accessor is now checking the passcode, we can modify the passcode and see that when it doesn't match we instead get the alert box warning us we don't have access to update the employee. - -Note: Accessors require you to set the compiler to output ECMAScript 5. - -# Static Properties - -Up to this point, we've only talked about the _instance_ members of the class, those that show up on the object when its instantiated. We can also create _static_ members of a class, those that are visible on the class itself rather than on the instances. In this example, we use 'static' on the origin, as it's a general value for all grids. Each instance accesses this value through prepending the name of the class. Similarly to prepending 'this.' in front of instance accesses, here we prepend 'Grid.' in front of static accesses. - -```TypeScript -class Grid { - static origin = {x: 0, y: 0}; - calculateDistanceFromOrigin(point: {x: number; y: number;}) { - var xDist = (point.x - Grid.origin.x); - var yDist = (point.y - Grid.origin.y); - return Math.sqrt(xDist * xDist + yDist * yDist) / this.scale; - } - constructor (public scale: number) { } -} - -var grid1 = new Grid(1.0); // 1x scale -var grid2 = new Grid(5.0); // 5x scale - -alert(grid1.calculateDistanceFromOrigin({x: 10, y: 10})); -alert(grid2.calculateDistanceFromOrigin({x: 10, y: 10})); -``` - -# Advanced Techniques - -## Constructor functions - -When you declare a class in TypeScript, you are actually creating multiple declarations at the same time. The first is the type of the _instance_ of the class. - -```TypeScript -class Greeter { - greeting: string; - constructor(message: string) { - this.greeting = message; - } - greet() { - return "Hello, " + this.greeting; - } -} - -var greeter: Greeter; -greeter = new Greeter("world"); -alert(greeter.greet()); -``` - -Here, when we say 'var greeter: Greeter', we're using Greeter as the type of instances of the class Greeter. This is almost second nature to programmers from other object-oriented languages. - -We're also creating another value that we call the _constructor function_. This is the function that is called when we 'new' up instances of the class. To see what this looks like in practice, let's take a look at the JavaScript created by the above example: - -```TypeScript -var Greeter = (function () { - function Greeter(message) { - this.greeting = message; - } - Greeter.prototype.greet = function () { - return "Hello, " + this.greeting; - }; - return Greeter; -})(); - -var greeter; -greeter = new Greeter("world"); -alert(greeter.greet()); -``` - -Here, 'var Greeter' is going to be assigned the constructor function. When we call 'new' and run this function, we get an instance of the class. The constructor function also contains all of the static members of the class. Another way to think of each class is that there is an _instance_ side and a _static_ side. - -Let's modify the example a bit to show this difference: - -```TypeScript -class Greeter { - static standardGreeting = "Hello, there"; - greeting: string; - greet() { - if (this.greeting) { - return "Hello, " + this.greeting; - } - else { - return Greeter.standardGreeting; - } - } -} - -var greeter1: Greeter; -greeter1 = new Greeter(); -alert(greeter1.greet()); - -var greeterMaker: typeof Greeter = Greeter; -greeterMaker.standardGreeting = "Hey there!"; -var greeter2:Greeter = new greeterMaker(); -alert(greeter2.greet()); -``` - -In this example, 'greeter1' works similarly to before. We instantiate the 'Greeter' class, and use this object. This we have seen before. - -Next, we then use the class directly. Here we create a new variable called 'greeterMaker'. This variable will hold the class itself, or said another way its constructor function. Here we use 'typeof Greeter', that is "give me the type of the Greeter class itself" rather than the instance type. Or, more precisely, "give me the type of the symbol called Greeter", which is the type of the constructor function. This type will contain all of the static members of Greeter along with the constructor that creates instances of the Greeter class. We show this by using 'new' on 'greeterMaker', creating new instances of 'Greeter' and invoking them as before. - -## Using a class as an interface - -As we said in the previous section, a class declaration creates two things: a type representing instances of the class and a constructor function. Because classes create types, you can use them in the same places you would be able to use interfaces. - -```TypeScript -class Point { - x: number; - y: number; -} - -interface Point3d extends Point { - z: number; -} - -var point3d: Point3d = {x: 1, y: 2, z: 3}; -``` diff --git a/Coding-guidelines.md b/Coding-guidelines.md index 8046c22a..a2bcb35b 100644 --- a/Coding-guidelines.md +++ b/Coding-guidelines.md @@ -1,35 +1,50 @@ +# ***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. +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. +6. Do not use `_` as a prefix for private properties. 7. Use whole words in names when possible. -## Components +## 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. +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'. +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. +## `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. +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 Boolean properties on a type should be turned into 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. @@ -58,22 +73,22 @@ Diagnostics are categorized into general ranges. If adding a new diagnostic mess For a variety of reasons, we avoid certain constructs, and use some of our own. Among them: -1. Do not use ECMAScript 5 functions; instead use those found in [core.ts](https://github.com/Microsoft/TypeScript/blob/master/src/compiler/core.ts). -2. Do not use `for..in` statements; instead, use `ts.forEach`, `ts.forEachKey` and `ts.forEachValue`. Be aware of their slightly different semantics. -3. Try to use `ts.forEach`, `ts.map`, and `ts.filter` instead of loops when it is not strongly inconvenient. +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: - 1. `x => x + x` - 2. `(x,y) => x + y` - 3. `(x: T, y: T) => x === y` -3. Always surround loop and conditional bodies with curly braces. + - `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: - 1. `for (var i = 0, n = str.length; i < 10; i++) { }` - 2. `if (x < 10) { }` - 3. `function f(x: number, y: string): void { }` + - `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. \ No newline at end of file +7. `else` goes on a separate line from the closing curly brace. +8. Use 4 spaces per indentation. diff --git a/Common-Errors.md b/Common-Errors.md index 3d60b868..416ed3e5 100644 --- a/Common-Errors.md +++ b/Common-Errors.md @@ -1,14 +1 @@ -# Introduction - -The list below captures some of the commonly confusing error messages that you may encounter when using the TypeScript language and Compiler - -# Commonly Confusing Errors -## "tsc.exe" exited with error code 1. - -*Fixes:* -* check file-encoding is UTF-8 - https://typescript.codeplex.com/workitem/1587 - -## external module XYZ cannot be resolved - -*Fixes:* -* check if module path is case-sensitive - https://typescript.codeplex.com/workitem/2134 +Deprecated doc \ No newline at end of file diff --git a/Compiler-Internals.md b/Compiler-Internals.md new file mode 100644 index 00000000..488b51e8 --- /dev/null +++ b/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/Compiler-Options.md b/Compiler-Options.md index e3f2167a..fc20565a 100644 --- a/Compiler-Options.md +++ b/Compiler-Options.md @@ -1,44 +1 @@ -## Compiler Options -Option | Shorthand | Description ---------|-------|-------------- -`--declaration` | `--d` | Generates corresponding '.d.ts' file. -`--help` | `--h` | Print help message. -`--version` | `--v` | Print the compiler's version. -`--module` | `--m` | Specify module code generation: 'commonjs', 'amd', 'system'[2], or 'umd'[2]. -`--project` | `--p` | Compile the project in the given directory. The directory needs to contain a `tsconfig.json` file to direct compilation. See [[tsconfig.json]] documentation for more details. -`--target` | `--t` | Specify ECMAScript target version: 'ES3' (default), 'ES5', or 'ES6'[1] -`--watch` | `--w` | Run the compiler in watch mode. Watch input files and trigger recompilation on changes. -`--charset` | | The character set of the input files. -`--diagnostics` | | Show diagnostic information. -`--emitBOM` | | Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. -`--emitDecoratorMetadata`[1][2] | | Emit design-type metadata for decorated declarations in source. See [issue #2577](https://github.com/Microsoft/TypeScript/issues/2577) for details. -`--inlineSourceMap`[2] | | Emit a single file with source maps instead of having a separate file. -`--inlineSources`[2] | | Emit the source alongside the sourcemaps within a single file; requires `--inlineSourceMap` to be set. -`--isolatedModules`[2] | | Unconditionally emit imports for unresolved files. -`--listFiles` | | Print names of files part of the compilation. -`--locale` | | The locale to use to show error messages, e.g. en-us. -`--mapRoot` | | Specifies the location where debugger should locate map files instead of generated locations. Use this flag if the .map files will be located at run-time in a different location than than the .js files. The location specified will be embedded in the sourceMap to direct the debugger where the map files where be located. -`--newLine`[2] | | Specifies the end of line sequence to be used when emitting files: 'CRLF' (dos) or 'LF' (unix)." -`--noEmit` | | Do not emit outputs. -`--noEmitOnError` | | Do not emit outputs if any type checking errors were reported. -`--noEmitHelpers` | | Do not generate custom helper functions like `__extends` in compiled output. -`--noImplicitAny` | | Raise error on expressions and declarations with an implied 'any' type. -`--noLib` | | Do not include the default library file (lib.d.ts). -`--noResolve` | | Do not add triple-slash references or module import targets to the list of compiled files. -`--out` | | Concatenate and emit output to single file. The order of concatenation is determined by the list of files passed to the compiler on the command line along with triple-slash references and imports. See output file order documentation for more details. -`--outDir` | | Redirect output structure to the directory. -`--preserveConstEnums` | | Do not erase const enum declarations in generated code. See [const enums documentation](https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md#94-constant-enum-declarations) for more details. -`--removeComments` | | Do not emit comments to output. -`--rootDir`[2] | | Specifies the root directory of input files. Use to control the output directory structure with `--outDir`. -`--sourceMap` | | Generates corresponding '.map' file. -`--sourceRoot` | | Specifies the location where debugger should locate TypeScript files instead of source locations. Use this flag if the sources will be located at run-time in a different location than that at design-time. The location specified will be embedded in the sourceMap to direct the debugger where the source files where be located. -`--stripInternal`[1] | | Do not emit declarations for code that has an `@internal` annotation. -`--suppressImplicitAnyIndexErrors` | | Suppress `--noImplicitAny` errors for indexing objects lacking index signatures. See [issue #1232](https://github.com/Microsoft/TypeScript/issues/1232#issuecomment-64510362) for more details. - -[1] These options are experimental. - -[2] These options will only be available in TypeScript 1.5. - -## Related - - For tsconfig.json see [[tsconfig.json]] - - For Setting the compiler options in MSBuild projects see [[Setting Compiler Options in MSBuild projects]] +> ### This page has moved to http://www.typescriptlang.org/docs/handbook/compiler-options.html \ No newline at end of file diff --git a/Configuring-MSBuild-projects-to-use-NuGet.md b/Configuring-MSBuild-projects-to-use-NuGet.md new file mode 100644 index 00000000..5789089d --- /dev/null +++ b/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/Contributing-to-TypeScript.md b/Contributing-to-TypeScript.md index 6ca36152..8e29f4f6 100644 --- a/Contributing-to-TypeScript.md +++ b/Contributing-to-TypeScript.md @@ -1,15 +1,21 @@ 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/master/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]]. + +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. @@ -20,7 +26,7 @@ We'll be using Labels to track the status of suggestions or feature requests. Yo * `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 - * `Accepting PRs`: We are accepting pull requests that fully implement this feature + * `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: @@ -31,12 +37,17 @@ Declined suggestions will have the `Declined` label along with one of the follow 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 +* 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/Debugging-Language-Service-in-VS-Code.md b/Debugging-Language-Service-in-VS-Code.md new file mode 100644 index 00000000..91a04e72 --- /dev/null +++ b/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/Declaration-Merging.md b/Declaration-Merging.md deleted file mode 100644 index a506bfd9..00000000 --- a/Declaration-Merging.md +++ /dev/null @@ -1,200 +0,0 @@ -# Introduction - -Some of the unique concepts in TypeScript comes from the necessity of describing what is happening to the shape of JavaScript objects at the type level. One example that is especially unique to TypeScript is the concept of 'declaration merging'. Understanding this concept will give you an advantage when working with existing JavaScript in your TypeScript. It also opens the door to more advanced abstraction concepts. - -First, before we get into how declarations merge, let's first describe what we mean by 'declaration merging'. - -For the purposes of this article, declaration merging specifically means that the compiler is doing the work of merging two separate declarations declared with the same name into a single definition. This merged definition has the features of both of the original declarations. Declaration merging is not limited to just two declarations, as any number of declarations can be merged. - -# Basic Concepts - -In TypeScript, a declaration exists in one of three groups: namespace/module, type, or value. Declarations that create a namespace/module are accessed using a dotted notation when writing a type. Declarations that create a type do just that, create a type that is visible with the declared shape and bound to the given name. Lastly, declarations create a value are those that are visible in the output JavaScript (eg, functions and variables). - - - - - - - - - - - - - - - - - - - - -
Declaration TypeNamespaceTypeValue
Module X X
Class X X
Interface X
Function X
Variable X
- -Understanding what is created with each declaration will help you understand what is merged when you perform a declaration merge. - -# Merging Interfaces - -The simplest, and perhaps most common, type of declaration merging is interface merging. At the most basic level, the merge mechanically joins the members of both declarations into a single interface with the same name. - -```TypeScript -interface Box { - height: number; - width: number; -} - -interface Box { - scale: number; -} - -var box: Box = {height: 5, width: 6, scale: 10}; -``` - -Non-function members of the interfaces must be unique. The compiler will issue an error if the interfaces both declare a non-function member of the same name. - -For function members, each function member of the same name is treated as describing an overload of the same function. Of note, too, is that in the case of interface A merging with later interface A (here called A'), the overload set of A' will have a higher precedence than that of interface A. - -That is, in the example: - -```TypeScript -interface Document { - createElement(tagName: any): Element; -} -interface Document { - createElement(tagName: string): HTMLElement; -} -interface Document { - createElement(tagName: "div"): HTMLDivElement; - createElement(tagName: "span"): HTMLSpanElement; - createElement(tagName: "canvas"): HTMLCanvasElement; -} -``` - -The two interfaces will merge to create a single declaration. Notice that the elements of each group maintains the same order, just the groups themselves are merged with later overload sets coming first: - -```TypeScript -interface Document { - createElement(tagName: "div"): HTMLDivElement; - createElement(tagName: "span"): HTMLSpanElement; - createElement(tagName: "canvas"): HTMLCanvasElement; - createElement(tagName: string): HTMLElement; - createElement(tagName: any): Element; -} -``` - -# Merging Modules - -Similarly to interfaces, modules of the same name will also merge their members. Since modules create both a namespace and a value, we need to understand how both merge. - -To merge the namespaces, type definitions from exported interfaces declared in each module are themselves merged, forming a single namespace with merged interface definitions inside. - -To merge the value, at each declaration site, if a module already exists with the given name, it is further extended by taking the existing module and adding the exported members of the second module to the first. - -The declaration merge of 'Animals' in this example: - -```TypeScript -module Animals { - export class Zebra { } -} - -module Animals { - export interface Legged { numberOfLegs: number; } - export class Dog { } -} -``` - -is equivalent to: - -```TypeScript -module Animals { - export interface Legged { numberOfLegs: number; } - - export class Zebra { } - export class Dog { } -} -``` - -This model of module merging is a helpful starting place, but to get a more complete picture we need to also understand what happens with non-exported members. Non-exported members are only visible in the original (un-merged) module. This means that after merging, merged members that came from other declarations can not see non-exported members. - -We can see this more clearly in this example: - -```TypeScript -module Animal { - var haveMuscles = true; - - export function animalsHaveMuscles() { - return haveMuscles; - } -} - -module Animal { - export function doAnimalsHaveMuscles() { - return haveMuscles; // <-- error, haveMuscles is not visible here - } -} -``` - -Because haveMuscles is not exported, only the animalsHaveMuscles function that shares the same un-merged module can see the symbol. The doAnimalsHaveMuscles function, even though it's part of the merged Animal module can not see this un-exported member. - -# Merging Modules with Classes, Functions, and Enums - -Modules are flexible enough to also merge with other types of declarations. To do so, the module declaration must follow the declaration it will merge with. The resulting declaration has properties of both declaration types. TypeScript uses this capability to model some of patterns in JavaScript as well as other programming languages. - -The first module merge we'll cover is merging a module with a class. This gives the user a way of describing inner classes. - -```TypeScript -class Album { - label: Album.AlbumLabel; -} -module Album { - export class AlbumLabel { } -} -``` - -The visibility rules for merged members is the same as described in the 'Merging Modules' section, so we must export the AlbumLabel class for the merged class to see it. The end result is a class managed inside of another class. You can also use modules to add more static members to an existing class. - -In addition to the pattern of inner classes, you may also be familiar with JavaScript practice of creating a function and then extending the function further by adding properties onto the function. TypeScript uses declaration merging to build up definitions like this in a type-safe way. - -```TypeScript -function buildLabel(name: string): string { - return buildLabel.prefix + name + buildLabel.suffix; -} - -module buildLabel { - export var suffix = ""; - export var prefix = "Hello, "; -} - -alert(buildLabel("Sam Smith")); -``` - -Similarly, modules can be used to extend enums with static members: - -```TypeScript -enum Color { - red = 1, - green = 2, - blue = 4 -} - -module Color { - export function mixColor(colorName: string) { - if (colorName == "yellow") { - return Color.red + Color.green; - } - else if (colorName == "white") { - return Color.red + Color.green + Color.blue; - } - else if (colorName == "magenta") { - return Color.red + Color.blue; - } - else if (colorName == "cyan") { - return Color.green + Color.blue; - } - } -} -``` - -# Disallowed Merges - -Not all merges are allowed in TypeScript. Currently, classes can not merge with other classes, variables and classes can not merge, nor can interfaces and classes. For information on mimicking classes merging, see the [Mixins](Mixins) section. \ No newline at end of file diff --git a/Dev-Mode-in-Visual-Studio.md b/Dev-Mode-in-Visual-Studio.md deleted file mode 100644 index 0f88668f..00000000 --- a/Dev-Mode-in-Visual-Studio.md +++ /dev/null @@ -1,60 +0,0 @@ -Dev Mode is a new feature for [TypeScript 1.4](https://github.com/Microsoft/TypeScript/releases/tag/v1.4) and higher that allows you to - -1. Debug the script side of the language service in Visual Studio. -2. Use a custom language service file of your choosing. - -# Enabling script debugging - -Note: You may also use the [VSDevMode.ps1](https://github.com/Microsoft/TypeScript/blob/master/scripts/VSDevMode.ps1) script to easily set these values. See the comments in the script for usage. - -1. Open up the Registry Editor (`regedit.exe` from the Run prompt). -2. If you are using... - * **Visual Studio 2013**: Navigate to `HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\12.0\TypeScriptLanguageService` (or create the key if it does not exist). - * **Visual Studio 2015**: Navigate to `HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\14.0\TypeScriptLanguageService` (or create the key if it does not exist). -3. Create a new DWORD (32-bit) Value with the name `EnableDevMode`. -4. Right click the `EnableDevMode` value and **Modify** it. -5. Change the value data to `1`. - -# Using a custom language service file - -Note: You may also use the [VSDevMode.ps1](https://github.com/Microsoft/TypeScript/blob/master/scripts/VSDevMode.ps1) script to easily set these values. See the comments in the script for usage. - -1. Open up the Registry Editor. -2. If you are using... - * **Visual Studio 2013**: Navigate to `HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\12.0\TypeScriptLanguageService` (or create the key if it does not exist). - * **Visual Studio 2015**: Navigate to `HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\14.0\TypeScriptLanguageService` (or create the key if it does not exist). -3. Create a new String Value with the name `CustomTypeScriptServicesFileLocation`. -4. Right click the `CustomTypeScriptServicesFileLocation` value and **Modify** it. -5. Change the value data to the full path of your alternative services file (e.g. `C:\Users\Daniel\TypeScript\built\local\typescriptServices.js`) - -# Hot swapping - -When the language service's script side is modified in any way (whether or not you are using a custom location for your language service file), it will be reloaded on the fly for a given thread the next time any of that thread's services are requested. However, this means that if debugging, your language service threads will be purged. - -# Debugging the language service in Visual Studio using Visual Studio - -1. Have a running instance of Visual Studio 2013/2015 with an open TypeScript file.
-![A running instance with a typical TypeScript file.](https://raw.githubusercontent.com/wiki/Microsoft/TypeScript/dev-mode-screenshots/001.png) -2. Open a new instance of Visual Studio 2013/2015. -3. Bring up the **Attach to Process** dialog by either - * Using menu bar and navigating from `Debug` -> `Attach to Process`.
- ![Navigating to the **Attach to Process** dialog with the menu bar.](https://raw.githubusercontent.com/wiki/Microsoft/TypeScript/dev-mode-screenshots/002.png) - * Clicking on the `Attach` button from the **Standard** toolbar if it is visible.
- ![A shortcut to opening the 'Attach to Process' dialog.](https://raw.githubusercontent.com/wiki/Microsoft/TypeScript/dev-mode-screenshots/003.png) -4. In the row labeled `Attach to:`, click on the `Select...` button.
- ![Hit the select button.](https://raw.githubusercontent.com/wiki/Microsoft/TypeScript/dev-mode-screenshots/004.png) -5. Click the radio button `Debug these code types` and select `Script`. Then press OK.
- ![Select 'Script' code to be debugged.](https://raw.githubusercontent.com/wiki/Microsoft/TypeScript/dev-mode-screenshots/005.png) -6. Find the appropriate Visual Studio instance in your list. Visual Studio instances have the process name `devenv.exe` and you can typically narrow down your instance looking for its current file in the Title field. -7. Hit the `Attach` button. In the **Solution Exporer**. you should now see four active debuggers (one for each language service thread).
- ![Debugging view after appropriately selecting your Visual Studio instance.](https://raw.githubusercontent.com/wiki/Microsoft/TypeScript/dev-mode-screenshots/006.png) - -At this point you should be able to hit debug points and get an understanding of what's going on. - -## Language Service Threads - -* **Classifier_N**: This thread runs the lexical classifier - a line-oriented classifier which is primarily concerned with fast rudimentary colorization. -* **LanguageService_N** and **LanguageService_N**: Unfortunately these haven't been distinctly named. - * One of these is the syntactic classifier, giving accurate (semantically agnostic) classifications. - * The other performs all syntax-related questions such as formatting, smart indentation, etc. -* **CoreServices_N**: This is used to perform semantic operations such as providing diagnostics, completion lists, quick info, etc. Effectively, anything that needs the typechecker will use this thread. \ No newline at end of file diff --git a/Docker-Quickstart.md b/Docker-Quickstart.md new file mode 100644 index 00000000..9a0451c4 --- /dev/null +++ b/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/FAQ.md b/FAQ.md new file mode 100644 index 00000000..9c5695bf --- /dev/null +++ b/FAQ.md @@ -0,0 +1,1832 @@ +# FAQ (For Issue Filers) + +FAQ Update 2024: The FAQ now attempts to only address content from people who end up filing GitHub issues. + +This is not intended to be a representative FAQ for TypeScript *in general*. + +## Common Feature Requests + +### Existing Common Requests + +Listed here (with some synonyms) for easier Ctrl-F-ing + + * Nominal types (tagged, branded): [#202](https://github.com/microsoft/TypeScript/issues/202) + * Negated types (not, exclusion, exclude, remove): [#4196](https://github.com/microsoft/TypeScript/issues/4196) + * Exact types (sealed, final, closed, unopen): [#12936](https://github.com/microsoft/TypeScript/issues/12936) + +## Behavior That Looks Wrong (And Arguably Is) But Is Currently Working As Intended + + * Method and function signatures behave differently, specifically that narrower argument types are unsoundly allowed in subtypes of methods, but not functions. See "Why Method Bivariance?" on this page + +## Pre-Declined Feature Requests + +### New Utility Types + +While `lib.d.ts` has some built-in types such as `Pick`, `Omit`, `Exclude`, `ReturnType`, etc., we are not accepting suggestions for adding new utility types. + +[Experience has taught us](https://github.com/microsoft/TypeScript/issues/30825) that defining utility types opens up a huge range of disagreement about very specific aspects of how these utility types should work, and once we ship a utility type, it's nearly always impossible to change it without causing many subtle breaks in user code. + +### Add a Key Constraint to `Omit` + +`Omit`s lack of key constraint is intentional. Many use cases for this type do not obey that constraint, e.g.: +```ts +type MySpread = T2 & Omit; +type X = MySpread<{ a: string, b: number}, { b: string, c: boolean }>; +let x: X = { a: "", b: "", c: true }; +``` + +You can write a user-space `Omit` type if you'd like to constrain the key. + +We also recommend using these definitions of a user-side `Pick` and `Omit` if desired: +```ts +type Pick_NewAndImproved = { + [P in keyof T as K & P]: T[P]; +}; + +// Optional: Add 'extends keyof T' constraint to K +type Omit_NewAndImproved = { + [P in keyof T as Exclude]: T[P]; } +} +``` + +### Module Specifier Rewriting + +It's explicitly out of scope for TypeScript to modify module specifiers as they appear in emitted JS, e.g. if you write + +```ts +import x from "some/path"; +``` + +the output specifier *will always be* `"some/path"` regardless of your tsconfig settings (with the exception of [`rewriteRelativeImportExtensions`](https://www.typescriptlang.org/tsconfig/#rewriteRelativeImportExtensions)). + +This includes things like changing file extensions, changing `paths` lookups to their resolutions, changing absolute paths to relative paths, changing relative paths to absolute paths, changing sub-module specifiers to something else, and so on. The string in the import path is the string in the emitted JavaScript, no exceptions. + +Instead of trying to get TypeScript to change the path during emit, the correct approach is to write the specifier you want to be in the output, and adjust your configuration until that specifier resolves (in type-land) to the path you want it to. + +See also: + + * [Module documentation](https://www.typescriptlang.org/docs/handbook/modules/theory.html#module-specifiers-are-not-transformed) + * [This comment](https://github.com/microsoft/TypeScript/issues/49083#issuecomment-1435399267) + +### Additional Logic in `noUncheckedIndexedAccess` + +`noUncheckedIndexedAccess` is intended to prevent all accidental out-of-bounds access on arrays. + +Because array mutation *could* occur at any time, it doesn't make any exceptions for things like `length` checks. + +In order to ensure that the flag doesn't have any "gaps", requests to change the logic to produce `T` instead of `T | undefined` will not be accepted. + +### `throws` / Checked Exceptions / Typed Exceptions + +[See this comment](https://github.com/microsoft/TypeScript/issues/13219#issuecomment-1515037604) + +## Common Misconceptions + +Note: Section titles here state the *true* version of the fact. + +## Comment Emit is Best-Effort + +When TypeScript emits JavaScript, it does not guarantee that 100% of source comments will be present in the output. +Not storing or computing comment ranges on emit is important for performance, and reasonable people can and do disagree about which comment blocks "belong" to either type (thus omitted) or expression (thus retained) constructs, so in general you should not take a hard dependency on comments being preserved or removed in arbitrary positions. + +You can *generally* expect comments to be preserved in cases where the comment immediately precedes a value declaration +```ts +// This comment will be in the output +const n = 5; +``` + +Comments will *generally* not be emitted when they occur inside types: +```ts +interface Foo { + // This comment won't be in the output + s: string; +} +``` + +If you need 100% comment preservation according to some definition of what should/shouldn't be emitted, we recommend using a different emit tool. +Edge cases or "inconsistencies" *will not be considered as defects*, and we don't accept PRs to tinker with comment emit. + +### Primitives are `{ }`, and `{ }` Doesn't Mean `object` + +The type `{ }` refers to any (non-null/undefined) value with zero or more properties. + +Primitive values, like strings, do have properties. For example, `"hello world".length` is a valid property access, because strings have a `length` property. Therefore, a `string` is a valid `{ }`: it is not null or undefined, and has zero or more properties. + +The type that refers to values which have `Object` in their prototype chain is `object`. `{ }` is not a synonym for `object`. + +### `{ }` Does Not Refer to Objects With No Properties + +Because TypeScript doesn't have sealed/closed types, there's no type which refers to values with zero properties. + +Certain [lint rules](https://github.com/typescript-eslint/typescript-eslint/issues/8700) ban using `{}`; we do not recommend this rule and we don't design the language around misguided lint rules. The correct value to use for "any non-null non-undefined value" is `{ }`, other suggested types like `Record` are not particularly coherent and shouldn't be used instead. We recommend disabling any lint rule that tries to prevent you from using `{ }`, because (unlike `String` or `Number`) it's a valid type that does occur in normal usage of TypeScript. + +### Evolving `let` and Evolving Arrays Aren't `any` + +Evolving `let` and evolving arrays are intentional (see PR #11263) and shouldn't be errors under `noImplicitAny`. They do not act like `any`. + +These features exist to ensure that these programs have equivalent behavior: +```ts +let x; +if (cond) { + x = y; +} else { + x = z; +} +doSomethingWith(x); // <- first read +``` +and the identical program: +```ts +let x = cond ? y : z; +doSomethingWith(x); +``` +Even those these appear as `any` in tooltips (see #54414), these don't have any of the problems associated with `any`. Allowing an assignment prior to the first read is no different from initialization and should be treated the same as initialization (and is). + +### (Indirect) Excess Properties Are OK + +Object types in TypeScript aren't "sealed" / "closed" / "final". In other words, if you have a variable of *type* `{ a: string }`, it's possible that the variable points to a *value* like `{ a: "hello", b: 42 }`. + +When you're directly creating an object literal, TypeScript uses "excess property checks" to detect likely problems: +```ts +interface Dimensions { + width: number; + height: number; + depth?: number; +} + +const p: Dimensions = { + width: 32, + height: 14, + depht: 11 // <-- typo!! +} +``` +However, this code is still legal: +```ts +const p = { + width: 32, + height: 14, + depht: 11 // <-- fine +}; +console.log(p.depht); // yep, it's there +const q: Dimensions = p; // also fine +``` + +This also means that `Object.keys` should (and does) return `string[]`, not `(keyof T)[]`. See also [this StackOverflow post](https://stackoverflow.com/questions/55012174/why-doesnt-object-keys-return-a-keyof-type-in-typescript) + +See also suggestion #12936 + +### `Number.isFinite` and `Number.isNaN` are Typed Correctly + +A dangerous thing that can happen in JavaScript is implicit coercion: +```ts +function quadruple(x) { + console.log((x + x) * 2); +} +quadruple("1"); // Prints 22, not 4 +``` +This happens because the value `"1"` adds to itself as string concat to produce `"11"`, which is then coerced to a number (`11`) before being multipled by `2`. + +You might try to use the global function `isFinite` to prevent this bug: +```ts +function quadruple(x) { + if (isFinite(x)) { + console.log((x + x) * 2); + } +} +quadruple("1"); // Still prints 22 +``` +This is because `isFinite` coerces its argument to a numeric value *before* evaluating if it's finite or not. +This is dangerous, because it can lead to unexpected results like the one above. + +The function `Number.isFinite` doesn't have this problem; it only returns `true` if its argument is actually a `number`: +```ts +function quadruple(x) { + if (Number.isFinite(x)) { + // Not reached + console.log((x + x) * 2); + } +} +quadruple("1"); // Safely does nothing +``` + +`isNaN` and `Number.isNaN` behave in a similar way; we know one property of the `NaN` value is that +```js +NaN !== NaN +``` +However, this property isn't true of values which pass `isNaN`: +```ts +const obj = {}; +if (isNaN(obj)) { + // prints true + console.log(obj === obj); +} +``` + +The TypeScript types for these functions *correctly* model the fact that you never want a dangerous coercion to occur: + * It's only safe to pass pre-coerced `number`s to the global `isFinite`. It always returns predictable, non-dangerous results *as long as* its input is a `number` + * Conversely, `Number.isFinite` will always give reliable results, because it does not perform coercion. It can safely accept any input as a result + +### Parameter Contravariance is Correct + +Let's say you write an interface +```ts +interface CanCheck { + checkThing: (x: string) => boolean; +} +``` +and implement it with an object: +```ts +const obj = { + checkThing: (sn: string | number) => { + return true; + } +} +obj satisfies CanCheck; // OK +``` + +A common confusion is to say that since `string | number` is a bigger type than `string`, this program should be rejected, since it means a number might appear where a string is expected. This reasoning is incorrect; even though a number can be passed to `obj.checkThing`, that cannot create the situation where a `number` is present somewhere where *only* a `string` is expected. + +Another common confusion is to claim that the opposite program should be accepted: +```ts +interface CanCheck { + checkThing: (x: string | number) => boolean; +} +const obj = { + checkThing: (s: string) => { + return true; + } +} +obj satisfies CanCheck; // Alleged: should be OK +``` +This is wrong. If `obj` is a `CanCheck`, then `obj.checkThing(42)` is legal, and `42` would appear in `s`, which is only allowed to be a `string`. + +Another common confusion is, in response, to say something like + +> But a function that takes a string *is* a function that takes a string or number! + +This is very, very easy to get backwards. After all, in common parlance, a "carnivore" is someone who eats meat. A person who eats beef would seem to qualify. Yet nearly every carnivore human does *not* eat human meat -- the predicate is not universal over all inputs. + +The correct way to phrase this is to insert the necessary qualifiers to the proposition + +> A function that can take **any** string is(?) a function that can take **any** string or number + +In this phrasing, the flaw is more apparent: Because the function *doesn't* take numbers, it doesn't match the criteria. + +This logic also applies equally to methods of classes that implement interfaces; no different behavior is required or justified here. + +### Parameter Arity Variance is Correct + +> 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. + +Let's consider another program first: +```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. + +If this *were* an error, it's not even clear how you would fix it! Adding the extra parameters is likely to run afoul of your linter: +```ts +let items = [1, 2, 3]; +// Error: Unused variables 'i', 'arr' +items.forEach((arg, i, arr) => console.log(arg)); +``` +JavaScript doesn't have a "discard" binding method, so you'd either end up with lint suppressions, or ugly and useless parameters: +```ts +// No one wants to write this sad code: +items.forEach((arg, _1, _2) => console.log(arg)); +``` + +> 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 +``` + +### `void` and `undefined` are Different + +`void` is not an alias for `undefined`. + +See [this StackOverflow answer](https://stackoverflow.com/a/58885486) + +See also #42709 + +### `Exclude` Isn't Type Negation + +`Exclude` isn't the same as `T & not U`. TypeScript does not yet have the notion of a negated type; see #4196. + +[As mentioned in the documentation](https://www.typescriptlang.org/docs/handbook/utility-types.html#excludeuniontype-excludedmembers), `Exclude` is a type alias whose *only* effect is to filter unions. This behavior comes from its [distributivity](https://www.typescriptlang.org/docs/handbook/2/conditional-types.html#distributive-conditional-types). It isn't a true "built-in" type that performs type negation. + +This means that if the input type isn't a union, nothing will happen. This includes types that you might think of as being "infinite unions", like `string` or `number` - they are not union types. + +For example, `Exclude` just means `string`. It doesn't mean "any `string` except `"hello"`", because `string` is not a union, and thus no filtering occurs. + +The same is true for numbers; `Exclude` is `number` because `number` is not a union. + +### `as` is the Casting Operator, So it Casts + +The `as` operator (and its other syntax, `expr`) is in the language *for the purpose* of downcasting, e.g. telling TypeScript that an `Animal` is actually a `Cat`. It's very easy to introduce runtime errors in your program via silencing a type error with a downcast, so care should be taken when using it. + +For convenience, this operator also works for upcasting, which is a much less frequently needed operation (usually `satisfies` is better). + +### The ECMAScript Spec is Descriptive, not Normative + +The ECMAScript spec defines the behavior of JavaScript runtime semantics. This means that even *clearly buggy* code, e.g.: +```ts +const output = "hello, world".substr("world"); +``` +has *a* defined behavior. + +The purpose of TypeScript isn't to tell you when you've somehow managed to reach outside the bounds of the ES Spec (a nearly impossible feat), nor to only tell you when you've done something that will raise a runtime exception (something that most people agree doesn't happen nearly often enough in JS). TypeScript defines a *normative* set of behaviors that we think are generally "good" JS - fewer (but not necessarily zero) implicit coercions, fewer property accesses that result in `undefined`, fewer exceptions, fewer `NaN`s, and so on. This does mean that some behavior is on the borderline of "good" vs "not so good", and there are judgement calls involved when it comes to what TypeScript thinks is OK or not. + +See also [this Stackoverflow Post](https://stackoverflow.com/a/41750391/) + +### `exclude` in `tsconfig.json` Only Filters `include` + +[As mentioned in the docs](https://www.typescriptlang.org/tsconfig#exclude), the `exclude` tsconfig option *only* filters the list of files that `include` picks up. It does not do anything else. Its only purpose is to change which files `include` produces, and doesn't change the behavior of any other processes. The only thing you can use `exclude` for is to have `include` not process a file; if the file is part of your program for a different reason, it will still be there. + +`exclude` has no effect on other ways a file might be included: + +* Module resolution +* The `files` list +* `/// 'foo' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer + +Due to the complexity of the checking process and caching, it's sometimes possible for a circularity error to occur in some situations but not others. If a codebase has a circularity in checking, that error *may* be issued, but it's also possible that you may be able to cause the error to go away by pre-doing part of the cycle elsewhere. + +In the interests of not arbitrarily breaking people, we're not accepting PRs to *add* more circularity errors. + +If you have a working PR that *removes* circularity errors without adverse side effects, we can review them. + +A very instructive deeper discussion can be read at [#45213](https://github.com/microsoft/TypeScript/issues/45213). + +### Comment Preservation Not Guaranteed + +As a trade-off to make parsing more efficient, TypeScript's emitter *may* not emit every comment in the original source. + +If your scenario requires every comment, or some particular form of comment, to be preserved, please use an alternate TS-to-JS transpiler. + +### Structural vs Instantiation-Based Inference + +Consider a function call where TypeScript must perform type inference: +```ts +type Box = { value: T }; +declare function unbox(arg: Box): T; + +function foo(x: Box) { + const a = unbox(x); // What is T? +} +``` + +There are two different approaches for inferring `T` you can use here: + * Option 1 (structural): Determine the structure of `Box`, see that it has a `{ value: string }` property, look at each property in `Box` seeing if it uses `T` in some position, notice that there's a `value: string` coming from `x` that corresponds to `value: T` in `Box`, therefore `T = string` + * Option 2 (instantiation-based): Notice that `Box` is an instantiation of `Box`, so `T = string` + +As one might expect, Option 2 is *much* faster, and is also equally correct. As such, TypeScript generally prefers this instantiation-based inference whenever possible. + +However, there are cases where instantiation and structural inference can produce different results. + +For example if `Box` doesn't actually *use* `T`, then a structurally-based inference will find no occurrences of `T` and infer `T = never`. *But* since there's never really a good reason to write a generic type this way, it's not considered to be problematic to do this. + +Which inference algorithm is chosen is implementation-dependent and may change for necessary correctness or performance reasons; you should not take a dependency on one or the other occurring. + +## Turn On This Flag To Do That + +Many bug reports simply require certain flags to be turned on to get the desired behavior. + +### Auto-import Heuristics and Preferences + +Auto-import is the feature that automatically suggests identifiers from other files that you may be able to `import` into the current file. It operates under a few key assumptions: + + 1. Your existing `import`s were written that way on purpose + 2. It's a bad idea to `import` things that won't work + 3. You don't want your laptop to start on fire + +Per the first point, when auto-import is choosing a way to refer to a module (there can often be more than one valid way), generally auto-import will try to use a module format that matches existing imports in the program. If this isn't available for whatever reason, the preferences `typescript.preferences.importModuleSpecifier` and `typescript.preferences.importModuleSpecifierEnding` +are consulted. You can change these settings to change how auto-import chooses how to refer to a module. + +On the second point, auto-import *intentionally* will not offer imports from packages that aren't listed as explicit dependencies in `package.json`, unless those packages have already been imported elsewhere in your code. This includes both *transitive* dependencies and `devDependencies`, since neither of those kind of dependencies are guaranteed to be present when your code is installed elsewhere. There isn't an option to configure this, since this only affects the very first time you import a module. + +Performance is also important. In situations where auto-import would traverse an impractically large amount of code from your `dependencies` list, it instead switches to only offering identifiers from already-imported modules. The current threshold for this is 25 packages. If you want to scan the entire dependencies list, change the `typescript.preferences.includePackageJsonAutoImports` setting from `auto` (the default) to `on`, or if you want to disable dependencies scanning altogether, change it to `off`. + +### Assume Array Access Might Be Out of Bounds: `noUncheckedIndexedAccess` + +You can turn on `noUncheckedIndexedAccess` to change the behavior such that arrays and object maps presume possibly-out-of-bounds access. + +This flag is a "big hammer", so to speak, and does not have any mechanisms for detecting provably in-bounds access. Because it's nearly impossible to soundly prove that an access is in-bounds (on account of mutation, etc.), such exceptions won't be considered. + +### Require Properties to Either Be Missing or Not `undefined`: `exactOptionalPropertyTypes` + +You can turn on `exactOptionalPropertyTypes` to change the behavior such that an optional property can't be explicitly provided with the value `undefined`. +This has important effects on things like object spread: +```ts +type Foo = { bar: number }; +const base: Foo = { bar: 42 }; +// Somewhat-suspect initialization of Partial +const partial: Partial = { bar: undefined }; + +// If using spread, the 'undefined' value can be present +// at Foo.bar +const possiblyBad: Foo = { ...base, ...partial }; +``` + +This flag affects *all* optional properties and there is no mechanism for doing this on a per-type basis. + +### Enforce `readonly` in Subtyping / Assignability + +Enable `--enforceReadonly` (not yet released; see [#58296](https://github.com/microsoft/TypeScript/pull/58296)) + +## Common Comments + +### What Kind of Feedback Are You Looking For? + +We greatly appreciate constructive and actionable feedback on all issues. Constructive and actionable means that we can read your comment and gain new information from it. + +Good examples of constructive and actionable feedback: + + * Code examples demonstrating how you would have used or been helped by the feature + * Examples of third-party libraries that already use patterns like this + * Describing where existing workarounds fall short of the desired behavior + +A good litmus test to see if feedback is useful is to consider the scenario where we have an idea for some feature *other* than exactly the one being proposed, and think it might solve the problem you're having when asking for a particular feature. If you just say "I need this feature", we can't look at your comment and evaluate if the other proposed feature would solve your problem. + +Similarly, the same feature request might have many different interpretations. If you just say "I need this", we don't know which *this* you're talking about, and can't figure out which interpretation of the feature is the correct one to implement. + +### Time Marches On + +Comments noting how long an suggestion has been open, what year it is, etc., are not considered constructive or helpful. We ask that you not bother posting them. + +Most programming languages in common use have been in development for decades at this point, and most common feature ideas can be noticed within the first couple years of use, so the only notable thing that we can deduce from a suggestion being longstanding is that the underlying language has withstood the test of time and is still in use *despite* lacking that feature - if anything, evidence against its priority. + +Similarly, in successful languages, most ideas that are easy and good get implemented quickly, so if you're looking at a longstanding issue, it's like either much more difficult or much less good than you might be thinking it is. Engaging with the problem, or providing useful context on why you think the change would be helpful, are constructive ways that you can comment on these threads. + +Extending long threads with unconstructive comments like this has many downsides: + + * Doesn't do anything to clarify why any particular change is more important than the thousands of other open suggestions (evolving a language is not a first-in first-out queue) + * Makes it harder to find useful content in the thread itself + * Adds noise to search results + * Increases the number of times someone has to click "Show More" once we reach the pagination limit + +### Can I Work On This? + +If this is in the `Backlog` milestone, yes! See also https://github.com/microsoft/TypeScript/blob/main/CONTRIBUTING.md#issue-claiming. Issues may also be marked with "Help Wanted" but this label is not necessary; the milestone field is authoritative. + +If an issue isn't in the `Backlog` milestone, please be advised that PRs may not be reviewed and may not be accepted. + +### Any Updates? + +There are generally no nonpublic updates that can be retrieved by asking "Any updates?". + +Our [iteration plans](https://github.com/microsoft/TypeScript/labels/Planning), [meeting notes](https://github.com/microsoft/TypeScript/labels/Design%20Notes), and other plans are available for perusal. + +If you'd like to see a particular bug fixed, feel free to raise it in the active milestone's iteration plan. We do our best to prioritize issues that people are encountering. + +If there are features you'd like to see added: + + * If it's in the `Backlog` milestone, PRs are welcomed! + * If it's not in the `Backlog` milestone, see "What Kind of Feedback Are You Looking For?" + +### This Is Closed, But Should Be Open, Or Vice Versa + +Every project on GitHub uses slightly different definitions of "Open" and "Closed". + +For us, "Open" means "There is known work left to do". An unfixed bug, for example, should be left open. A suggestion we're still working out the details on, or assessing the need for, is also likely to be Open. + +"Closed" means "There is not known work left to do". A fixed bug, for example, is always closed; there is nothing left to do. A suggestion which is clearly out-of-scope for the project, either by going against its core design principles, or being simply unrelated to its core goals, would also be closed. + +Not every example is clear-cut. As with all things in life, when there are grey areas to be found, and it's [hard to find definitions that everyone agrees with](https://danluu.com/impossible-agree/). + +These are the edge case rules that we've decided on for clarity: + + * A *bug* (i.e. known defect) that is so trivial as to not ever be bothersome (for example, a benign crash that only occurs in a file specifically crafted to overflow the parser stack) may be considered a "Won't Fix". In this case, it is *Closed* because there is not "work left to do" + * A *suggestion* (feature idea) that seems quite unlikely to provide a good return on investment in the foreseeable future would be Closed, because we've done the work (gathered feedback, considered the pros and cons, and made a decision) + * Sometimes the decision will be "Not right now, but definitely possibly later?" - in this case, Open is the correct state, because the work is "Keep collecting feedback to see how priorities change". A suggestion may be Open for a very long time as a result. We do not Close suggestions *simply* because they were brought up a long time ago, and don't Close issues simply because they haven't been done fast enough for someone's liking. + * A *design limitation* (acknowledged problem, but one where we have no idea how to fix it, or how to fix it without unacceptable downsides) is Closed. These are difficult cases where we've agreed that the issue is a problem *per se*, but can't see any solution that would be acceptable. There is no "work to be done" here because "Make a breakthrough" is not work that can be concretely pursued. + * If you think you have a solution to a problem marked "design limitation", feel free to send a PR, we will evaluate it. + +All decisions are "only for now". The JS ecosystem is ever-changing, developer priorities are ever-changing, and the project itself will always be evolving over time. This doesn't mean we need to leave *every* issue Open just to leave open a slight chance of a future possibility -- the "Re-open" button is always there, and we're always capable of changing our minds in the face of new evidence or new circumstances. Open/Closed in these gray areas represents *our best guess* at the long-term state of all of these decisions. + +It's worth noting that the Open/Close state flows *from* the maintainers' point of view *to* the issue, not vice versa. Reopening a Suggestion for a feature that we actively don't want to be part of the language won't make us start wanting it. Similarly, reopening a Design Limitation that we have no idea how to fix won't make us able to address it. + +Open/Closed definition is a project-wide decision and we don't make per-issue deviations from this definition. Complaining about open/closed state isn't constructive, and please remember that insistence in engaging in nonconstructive discussion is against the [code of conduct](https://microsoft.github.io/codeofconduct/). + +On a related note, this project does not use the "Closed as Completed" / "Closed as Not Planned" distinction, please do not consult this information. The "close reason" field was added in 2022 so all closed issues prior to that are marked as "Completed" even if nothing was done as a result. Additionally, for a long time thereafter, it wasn't possible to set this field when closing via automation, so auto-closed issues also have an incorrect "close reason". Please don't consult this field, draw any conclusions from it, or ask maintainers to change it -- we don't consult it, and we consider labels / discussion comments to be the correct source of truth as to why an issue was closed (setting aside the philosophical paradox of whether one can be said to have "completed" something involving zero planned work). + +## Other FAQs and Errors + +### Why Method Bivariance? + +It seems like it should be really easy to add a `--strictMethodTypes` flag that works just like `--strictFunctionTypes` does today. What's the problem? + +In short, even though this seems like it should be straightforward, there are a large number of common patterns today that depend on using method bivariance to cause types to subtype other types in ways that are idiomatic due to prior knowledge of ownership, conventions around who's allowed to raise event-like callbacks, and others. A cursory check in a small project shows hundreds of errors in longstanding code where there aren't any existing complaints of unsoundness due to bivariance. Without a way to fix these errors, there's not a tractable path forward to adding those errors in other places where bivariance definitely *is* a possible source of error. + +Out of the gate, this breaks array covariance, and not even in a way that has an apparent fix. Let's reduce `Array` and `ReadonlyArray` to their smallest representations relevant to the problem at hand: +```ts +// The smallest possible read-only array that still has +// a useful method for getting a mutable copy, like you +// would expect to be able to get from Array#slice +interface MiniatureReadonlyArray { + getMutableCopy(): MiniatureMutableArray; + readonly [i: number]: T; +} + +// Mutable array just adds one contravariant method +interface MiniatureMutableArray extends MiniatureReadonlyArray { + push(arg: T): void; +} + +// A read-only array of strings and numbers +declare const sn_mini: MiniatureReadonlyArray; +// A should-be-legal covariant aliasing of that array +let snb_mini: MiniatureReadonlyArray = sn_mini; +``` +Under `strictMethodTypes`, this assignment actually fails. Why? + +*It appears* that an illegal call is possible when you do this: +```ts +// Invalid: snb_mini is possibly an alias to sn_mini, +// whose getMutablyCopy's return type is MiniatureMutableArray, +// whose `push` method cannot accept booleans +snb_mini.getMutableCopy().push(true); +``` +This logic is sound given the definitions of types that we have. + +However, we (as humans) know from reading the prose that when we call `getMutableCopy`, the *copy* we get is something we're free to mutate however we like. + +Possible solutions to this problem are themselves quite difficult: + * One option would be to have some kind of per-site annotation so that we could say that `getMutableCopy` doesn't return a `MiniatureMutableArray`; instead it returns... well, something else. `MiniatureMutableArray< out T>` ? What are the semantics of this? When exactly is the covariant aliasing allowed? Can I get a reference to an `out string` if I start with a `MiniatureReadonlyArray`? When does that modifier go away? It's not clear. If I knew what to write here I'd be proposing it. + * Allow "forced" variance annotation, e.g. allow you to write something like `interface ReadonlyArray {` that forces a covariant measurement of `T`. This isn't great either, because it means that structural and instantiation-based inferences and relational checks on `ReadonlyArray` would behave differently (see the FAQ entry on this). Since there's no guarantee which of those two checks you get, this just opens the door for a huge amount of fundamentally-unfixable inconsistencies whenever this type gets mentioned, which is going to be very common. *Worse*, since `interface Array` and `interface ReadonlyArray` *are* different interfaces, any time you bridge the mutability gap, you'll see the invariant behavior instead of the covariant behavior (since a variance annotation can't apply to a structural operation), so this problem would not actually go away *at all*. + * Some kind of more-explicit "ownership" model like Rust's that gives more prescriptive rules around when something is allowed to be covariantly aliased and when it isn't. Again, I don't know what that looks like in TypeScript. + +This also breaks function intersection with the built-in `Function`, again with no clear fix: +```ts +type SomeFunc = (s: string) => void; +declare const sf: SomeFunc; +// Illegal +const p: Function & SomeFunc = sf; +``` +With the observed error - again, technically sound - that you can't call `p`'s `apply` method obtained from `Function` +``` +error TS2322: Type 'SomeFunc' is not assignable to type 'Function & SomeFunc'. + Type 'SomeFunc' is not assignable to type 'Function'. + Types of property 'apply' are incompatible. + Type '{ (this: (this: T) => R, thisArg: T): R; (this: (this: T, ...args: A) => R, thisArg: T, args: A): R; }' is not assignable to type '(this: Function, thisArg: any, argArray?: any) => any'. +``` + +Basic assignment to `readonly unknown[]` doesn't work, due to `concat`: +``` +error TS2322: Type 'readonly string[]' is not assignable to type 'readonly unknown[]'. + Types of property 'concat' are incompatible. + Type '{ (...items: ConcatArray[]): string[]; (...items: (string | ConcatArray)[]): string[]; }' is not assignable to type '{ (...items: ConcatArray[]): unknown[]; (...items: unknown[]): unknown[]; }'. + Types of parameters 'items' and 'items' are incompatible. + Type 'ConcatArray' is not assignable to type 'ConcatArray'. + The types returned by 'slice(...).pop()' are incompatible between these types. + Type 'unknown' is not assignable to type 'string | undefined'. + +``` + +There's also a problem with the DOM, because the DOM types are constructed in a way that implicitly disallows some operations via a supertype alias, e.g. `addEventListener` + +`@types/node` also produces hundreds of errors due to the eventing pattern, e.g. +``` +node_modules/@types/node/child_process.d.ts:73:15 - error TS2430: Interface 'ChildProcess' incorrectly extends interface 'EventEmitter'. + Types of property 'addListener' are incompatible. + Type '{ (event: string, listener: (...args: any[]) => void): this; (event: "close", listener: (code: number | null, signal: Signals | null) => void): this; (event: "disconnect", listener: () => void): this; (event: "error", listener: (err: Error) => void): this; (event: "exit", listener: (code: number | null, signal: Sign...' is not assignable to type '(eventName: string | symbol, listener: (...args: any[]) => void) => this'. + Types of parameters 'event' and 'eventName' are incompatible. + Type 'string | symbol' is not assignable to type 'string'. + Type 'symbol' is not assignable to type 'string'. + +73 interface ChildProcess extends EventEmitter { + ~~~~~~~~~~~~ +``` + +### What does error TS1287 mean? + +Search Terms: "A top-level 'export' modifier cannot be used on value declarations in a CommonJS module when 'verbatimModuleSyntax' is enabled."; +TypeScript 5.9: "A CommonJS module cannot use ESM syntax when 'verbatimModuleSyntax' is enabled. Consider adding "type": "module" to package.json" + +**TL;DR** + * If you're writing an ESM NodeJS app, add `"type": "module"` to `package.json` + * If you're not sure what to do, start by trying this + * If you're writing a CommonJS NodeJS app, either write `import fs = require("fs");` or disable `verbatimModuleSyntax` + * If you're using a bundler, change `module` to `preserve` in `tsconfig.json` + * If you're writing ESM directly for web, change `module` to `esnext` in `tsconfig.json` + +The `verbatimModuleSyntax` flag enforces that CommonJS (CJS) modules use CJS syntax (`import fs = require('fs');`), and ES Modules (ESM) use ESM syntax (`import * as fs from 'fs';`). +This is generally a good flag to enable, because some packages expose different API to CJS and ESM. +By enabling `verbatimModuleSyntax`, you can be sure that when you see CJS syntax you're getting the CJS version of the module, and likewise for ESM. + +However, two things interact in a way that can be surprising. + +The first fact is that most people tend to write ESM syntax these days. + +The second is that NodeJS has a complex set of rules for determining when a file with a .js extension is CJS or ESM: + + * If package.json doesn't exist, files are CJS unless they have a top-level import or export statement, in which case they're silently re-interpreted as ESM + * If package.json exists but has no `type` field, the same rule applies, except you'll see a warning on stdout + * Note that older versions of `npm init` do not set a `type` field + * If package.json exists and set `type`, the file is always of that type + * Newer versions of `npm init` set the `type` field to `"commonjs"` by default + +This means that unless you've explicitly taken some step to opt into ESM modules (either by setting `"type": "module" or naming your file `.mts`), Node.js will treat your files as CommonJS modules. + +### The inferred type of "X" cannot be named without a reference to "Y". This is likely not portable. A type annotation is necessary + +Let's say you use a package manager with strict dependencies: +``` +|-/my_package_1 +|-- /node_modules +|---- /other_package <- direct dependency +|------ index.d.ts +|------ /node_modules +|--------- /sub_dep <- symlink! +|----------- index.d.ts +|-- /src +|---- tsconfig.json <- project root +|---- foo.ts <- a source file that imports the above file +``` +Where `foo.ts` looks like this: +```ts +import { getMakeSubDep } from "other_package"; + +// The inferred type of p refers to a type defined +// inside node_modules/other_package/node_modules/sub_dep/index.d.ts +export const p = getMakeSubDep(); +``` +When TypeScript needs to emit `foo.d.ts`, it needs to write out a type for `p`: +```ts +export const p: ??? +``` + +What should go in the `???` ? + +One option would be to use a relative path: +```ts +import { subdep } from "../node_modules/other_package/node_modules/sub_dep"; +export const p: subdep +``` +This is *obviously* wrong: It's implausible that a consumer of `foo.d.ts` would have a folder layout that matches what we happened to have here. + +Another option would be to use a subpath: +```ts +import { subdep } from "other_package/node_modules/sub_dep"; +export const p: subdep +``` +This is *also* obviously wrong: The semantics of `other_package` are not that it exposes `node_modules/sub_dep` as as sub-path. This probably won't work at runtime, and even if it did, it's not what you want + +Another option would be to use a module name: +```ts +import { subdep } from "sub_dep"; +export const p: subdep +``` + +Is *this* correct? + +If `other_package` has a dependency on `sub_dep@2.0.0` and *your* package has a dependency on `sub_dep@3.0.0`, then these aren't the same type, and it's wrong. + +If you don't have a declared dependency on `sub_dep` at all, then this code would also fail to load `sub_dep` when ingested in a downstream project. + +These situations - the non-working ones - are the "non-portable identifiers" that TypeScript is complaining about. TS was put into a position where it had to reference the name of a module, but it couldn't find a name for that module that appeared to work. This is why this error occurs. + +Now, if you *do* have a declared dependency on `sub_dep`, and it resolves to the "same" target as the one `other_package` did, then this is fine. The way this works (roughly) is that TS keeps a reverse map of the files it has loaded and what module specifiers it used to find them. So if you have `import { subdep } from "sub_dep"`, and it resolved to a correct .d.ts file, then TS will have it in the lookup table and can use `sub_dep` to refer to the same file that `other_package` did even though these two module specifiers *may have* referred to different files (but they didn't). + +But! If you never referred to `sub_dep` in your compilation, then TypeScript has never "seen" `sub_dep` be referred to from the module resolution context that `foo.d.ts` will have, so it doesn't know whether or not `"sub_dep"` is a legal way to refer to `other_package/node_modules/sub_dep`, and ends up issuing this error. + +The correct way to address this is generally to import the type that the `.d.ts` needs to refer to: +```ts +// in foo.ts +import { subdep } from "sub_dep"; +import { getMakeSubDep } from "other_package"; + +// No additional type annotation needed +export const p = getMakeSubDep(); +``` +If *you* can't do this, then TypeScript can't either, and the only real alternative is to use a broader type annotation so that TS doesn't need to refer to types which are impossible to name: +```ts +// in foo.ts +import { getMakeSubDep } from "other_package"; + +// Annotate to anonymous version of whatever subdep is +export const p: { isSubDep: boolean } = getMakeSubDep(); +``` +Or restructure the input file in such a way that the referenced type is not exposed in the `.d.ts`. + +As of TypeScript 5.5 (see #58176), this error should never occur if the required dependency is in your project's `package.json`. + +-------------- + +# FAQ Archive + + + +## 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`, `nodenext` or `bundler` 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 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. +``` + +------------------------------------------------------------------------------------- + +## 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 `