diff --git a/pages/Basic Types.md b/pages/Basic Types.md index 0d40b5f2e..fab64ba57 100644 --- a/pages/Basic Types.md +++ b/pages/Basic Types.md @@ -190,6 +190,27 @@ Declaring variables of type `void` is not useful because you can only assign `un let unusable: void = undefined; ``` +# Null and Undefined + +In TypeScript, both `undefined` and `null` actually have their own types named `undefined` and `null` respectively. +Much like `void`, they're not extremely useful on their own: + +```ts +// Not much else we can assign to these variables! +let u: undefined = undefined; +let n: null = null; +``` + +By default `null` and `undefined` are subtypes of all other types. +That means you can assign `null` and `undefined` to something like `number`. + +However, when using the `--strictNullChecks` flag, `null` and `undefined` are only assignable to `void` and their respective types. +This helps avoid *many* common errors. +In cases where you want to pass in either a `string` or `null` or `undefined`, you can use the union type `string | null | undefined`. +Once again, more on union types later on. + +> As a note: we encourage the use of `--strictNullChecks` when possible, but for the purposes of this handbook, we will assume it is turned off. + # Type assertions Sometimes you'll end up in a situation where you'll know more about a value than TypeScript does. diff --git a/pages/Classes.md b/pages/Classes.md index 3e03784ee..2b508d010 100644 --- a/pages/Classes.md +++ b/pages/Classes.md @@ -189,27 +189,70 @@ console.log(howard.name); // error Notice that while we can't use `name` from outside of `Person`, we can still use it from within an instance method of `Employee` because `Employee` derives from `Person`. +A constructor may also be marked `protected`. +This means that the class cannot be instantiated outside of its containing class, but can be extended. For example, + +```ts +class Person { + protected name: string; + protected constructor(theName: string) { this.name = theName; } +} + +// Employee can extend Person +class Employee extends Person { + private department: string; + + constructor(name: string, department: string) { + super(name); + this.department = department; + } + + public getElevatorPitch() { + return `Hello, my name is ${this.name} and I work in ${this.department}.`; + } +} + +let howard = new Employee("Howard", "Sales"); +let john = new Person("John"); // Error: The 'Person' constructor is protected +``` + +# Readonly modifier + +You can make properties readonly by using the `readonly` keyword. +Readonly properties must be initialized at their declaration or in the constructor. + +```ts +class Octopus { + readonly name: string; + readonly numberOfLegs: number = 8; + constructor (theName: string) { + this.name = theName; + } +} +let dad = new Octopus("Man with the 8 strong legs"); +dad.name = "Man with the 3-piece suit"; // error! name is readonly. +``` + ## Parameter properties -In our last example, we had to declare a private member `name` and a constructor parameter `theName`, and we then immediately set `name` to `theName`. +In our last example, we had to declare a readonly member `name` and a constructor parameter `theName` in the `Octopus` class, and we then immediately set `name` to `theName`. This turns out to be a very common practice. *Parameter properties* let you create and initialize a member in one place. -Here's a further revision of the previous `Animal` class using a parameter property: +Here's a further revision of the previous `Octopus` class using a parameter property: ```ts -class Animal { - constructor(private name: string) { } - move(distanceInMeters: number) { - console.log(`${this.name} moved ${distanceInMeters}m.`); +class Octopus { + readonly numberOfLegs: number = 8; + constructor(readonly name: string) { } } ``` -Notice how we dropped `theName` altogether and just use the shortened `private name: string` parameter on the constructor to create and initialize the `name` member. +Notice how we dropped `theName` altogether and just use the shortened `readonly name: string` parameter on the constructor to create and initialize the `name` member. We've consolidated the declarations and assignment into one location. -Parameter properties are declared by prefixing a constructor parameter with an accessibility modifier. -Using `private` for a parameter property declares and initializes a private member; likewise, the same is done for `public` and `protected`. +Parameter properties are declared by prefixing a constructor parameter with an accessibility modifier or `readonly`, or both. +Using `private` for a parameter property declares and initializes a private member; likewise, the same is done for `public`, `protected`, and `readonly`. # Accessors @@ -266,7 +309,12 @@ if (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 message warning us we don't have access to update the employee. -Note: Accessors require you to set the compiler to output ECMAScript 5 or higher. +A couple of things to note about accessors: + +First, accessors require you to set the compiler to output ECMAScript 5 or higher. +Downlevelling to ECMAScript 3 is not supported. +Second, accessors with a `get` and no `set` are automatically inferred to be `readonly`. +This is helpful when generating a `.d.ts` file from your code, because users of your property can see that they can't change it. # Static Properties diff --git a/pages/Compiler Options in MSBuild.md b/pages/Compiler Options in MSBuild.md index 8ef72c22a..b162f3030 100644 --- a/pages/Compiler Options in MSBuild.md +++ b/pages/Compiler Options in MSBuild.md @@ -22,52 +22,68 @@ Compiler options can be specified using MSBuild properties within an MSBuild pro Compiler Option | MSBuild Property Name | Allowed Values ---------------------------------------------|--------------------------------------------|----------------- -`--declaration` | TypeScriptGeneratesDeclarations | boolean -`--module` | TypeScriptModuleKind | `AMD`, `CommonJs`, `UMD`, or `System` -`--target` | TypeScriptTarget | `ES3`, `ES5`, or `ES6` +`--allowJs` | *Not supported in MSBuild* | +`--allowSyntheticDefaultImports` | TypeScriptAllowSyntheticDefaultImports | boolean +`--allowUnreachableCode` | TypeScriptAllowUnreachableCode | boolean +`--allowUnusedLabels` | TypeScriptAllowUnusedLabels | boolean +`--baseUrl` | TypeScriptBaseUrl | File path `--charset` | TypeScriptCharset | +`--declaration` | TypeScriptGeneratesDeclarations | boolean +`--declarationDir` | TypeScriptDeclarationDir | File path +`--diagnostics` | *Not supported in MSBuild* | `--emitBOM` | TypeScriptEmitBOM | boolean `--emitDecoratorMetadata` | TypeScriptEmitDecoratorMetadata | boolean +`--experimentalAsyncFunctions` | TypeScriptExperimentalAsyncFunctions | boolean `--experimentalDecorators` | TypeScriptExperimentalDecorators | boolean +`--forceConsistentCasingInFileNames` | TypeScriptForceConsistentCasingInFileNames | boolean +`--help` | *Not supported in MSBuild* | `--inlineSourceMap` | TypeScriptInlineSourceMap | boolean `--inlineSources` | TypeScriptInlineSources | boolean +`--init` | *Not supported in MSBuild* | +`--isolatedModules` | TypeScriptIsolatedModules | boolean +`--jsx` | TypeScriptJSXEmit | `React` or `Preserve` +`--lib` | TypeScriptLib | Comma-separated list of strings +`--listEmittedFiles` | *Not supported in MSBuild* | +`--listFiles` | *Not supported in MSBuild* | `--locale` | *automatic* | Automatically set to PreferredUILang value `--mapRoot` | TypeScriptMapRoot | File path +`--module` | TypeScriptModuleKind | `AMD`, `CommonJs`, `UMD`, `System` or `ES6` +`--moduleResolution` | TypeScriptModuleResolution | `Classic` or `Node` `--newLine` | TypeScriptNewLine | `CRLF` or `LF` -`--noEmitOnError` | TypeScriptNoEmitOnError | boolean +`--noEmit` | *Not supported in MSBuild* | `--noEmitHelpers` | TypeScriptNoEmitHelpers | boolean +`--noEmitOnError` | TypeScriptNoEmitOnError | boolean +`--noFallthroughCasesInSwitch` | TypeScriptNoFallthroughCasesInSwitch | boolean `--noImplicitAny` | TypeScriptNoImplicitAny | boolean +`--noImplicitReturns` | TypeScriptNoImplicitReturns | boolean +`--noImplicitThis` | TypeScriptNoImplicitThis | boolean +`--noImplicitUseStrict` | TypeScriptNoImplicitUseStrict | boolean `--noLib` | TypeScriptNoLib | boolean `--noResolve` | TypeScriptNoResolve | boolean `--out` | TypeScriptOutFile | File path `--outDir` | TypeScriptOutDir | File path +`--outFile` | TypeScriptOutFile | File path +`--paths` | *Not supported in MSBuild* | `--preserveConstEnums` | TypeScriptPreserveConstEnums | boolean +`--listEmittedFiles` | *Not supported in MSBuild* | +`--pretty` | *Not supported in MSBuild* | +`--reactNamespace` | TypeScriptReactNamespace | string `--removeComments` | TypeScriptRemoveComments | boolean `--rootDir` | TypeScriptRootDir | File path -`--isolatedModules` | TypeScriptIsolatedModules | boolean +`--rootDirs` | *Not supported in MSBuild* | +`--skipLibCheck` | TypeScriptSkipLibCheck | boolean +`--skipDefaultLibCheck` | TypeScriptSkipDefaultLibCheck | boolean `--sourceMap` | TypeScriptSourceMap | File path `--sourceRoot` | TypeScriptSourceRoot | File path -`--suppressImplicitAnyIndexErrors` | TypeScriptSuppressImplicitAnyIndexErrors | boolean +`--strictNullChecks` | TypeScriptStrictNullChecks | File path `--suppressExcessPropertyErrors` | TypeScriptSuppressExcessPropertyErrors | boolean -`--moduleResolution` | TypeScriptModuleResolution | `Classic` or `Node` -`--experimentalAsyncFunctions` | TypeScriptExperimentalAsyncFunctions | boolean -`--jsx` | TypeScriptJSXEmit | `React` or `Preserve` -`--reactNamespace` | TypeScriptReactNamespace | string -`--skipDefaultLibCheck` | TypeScriptSkipDefaultLibCheck | boolean -`--allowUnusedLabels` | TypeScriptAllowUnusedLabels | boolean -`--noImplicitReturns` | TypeScriptNoImplicitReturns | boolean -`--noFallthroughCasesInSwitch` | TypeScriptNoFallthroughCasesInSwitch | boolean -`--allowUnreachableCode` | TypeScriptAllowUnreachableCode | boolean -`--forceConsistentCasingInFileNames` | TypeScriptForceConsistentCasingInFileNames | boolean -`--allowSyntheticDefaultImports` | TypeScriptAllowSyntheticDefaultImports | boolean -`--noImplicitUseStrict` | TypeScriptNoImplicitUseStrict | boolean -`--project` | *Not supported in VS* | -`--watch` | *Not supported in VS* | -`--diagnostics` | *Not supported in VS* | -`--listFiles` | *Not supported in VS* | -`--noEmit` | *Not supported in VS* | -`--allowJs` | *Not supported in VS* | -*VS only option* | TypeScriptAdditionalFlags | *Any compiler option* +`--suppressImplicitAnyIndexErrors` | TypeScriptSuppressImplicitAnyIndexErrors | boolean +`--target` | TypeScriptTarget | `ES3`, `ES5`, or `ES6` +`--traceResolution` | *Not supported in MSBuild* | +`--types` | *Not supported in MSBuild* | +`--typeRoots` | *Not supported in MSBuild* | +`--watch` | *Not supported in MSBuild* | +*MSBuild only option* | TypeScriptAdditionalFlags | *Any compiler option* ## What is supported in my version of Visual Studio? @@ -86,4 +102,4 @@ Users using newer versions of TS, will see a prompt to upgrade their project on ## TypeScriptCompileBlocked If you are using a different build tool to build your project (e.g. gulp, grunt , etc.) and VS for the development and debugging experience, set `true` in your project. -This should give you all the editing support, but not the build when you hit F5. \ No newline at end of file +This should give you all the editing support, but not the build when you hit F5. diff --git a/pages/Compiler Options.md b/pages/Compiler Options.md index 531f969f5..c7cba7d9d 100644 --- a/pages/Compiler Options.md +++ b/pages/Compiler Options.md @@ -4,10 +4,12 @@ Option | Type | Default -----------------------------------------------|-----------|--------------------------------|---------------------------------------------------------------------- `--allowJs` | `boolean` | `true` | Allow JavaScript files to be compiled. `--allowSyntheticDefaultImports` | `boolean` | `(module === "system")` | Allow default imports from modules with no default export. This does not affect code emit, just typechecking. -`--allowUnreachableCode` | `boolean` | `false` | Do not report errors on unreachable code. +`--allowUnreachableCode` | `boolean` | `false` | Do not report errors on unreachable code. `--allowUnusedLabels` | `boolean` | `false` | Do not report errors on unused labels. +`--baseUrl` | `string` | | Base directory to resolve non-relative module names. See [Module Resolution documentation](./Module Resolution.md#base-url) for more details. `--charset` | `string` | `"utf8"` | The character set of the input files. `--declaration`
`-d` | `boolean` | `false` | Generates corresponding '.d.ts' file. +`--declarationDir` | `string` | | Output directory for generated declaration files. `--diagnostics` | `boolean` | `false` | Show diagnostic information. `--emitBOM` | `boolean` | `false` | Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. `--emitDecoratorMetadata`[1] | `boolean` | `false` | Emit design-type metadata for decorated declarations in source. See [issue #2577](https://github.com/Microsoft/TypeScript/issues/2577) for details. @@ -19,11 +21,13 @@ Option | Type | Default `--init` | | | Initializes a TypeScript project and creates a `tsconfig.json` file. `--isolatedModules` | `boolean` | `false` | Unconditionally emit imports for unresolved files. `--jsx` | `string` | `"Preserve"` | Support JSX in '.tsx' files: `'React'` or `'Preserve'`. See [JSX](./JSX.md). +`--lib` | `string[]`| | List of library files to be included in the compilation.
Possible values are:
► `es5`
► `es6`
► `es2015`
► `es7`
► `es2016`
► `es2017` `dom` `webworker` `scripthost`
► `es2015.core`
► `es2015.collection`
► `es2015.generator`
► `es2015.iterable`
► `es2015.promise`
► `es2015.proxy`
► `es2015.reflect`
► `es2015.symbol`
► `es2015.symbol.wellknown`
► `es2016.array.include`
► `es2017.object`
► `es2017.sharedmemory` +`--listEmittedFiles` | `boolean` | `false` | Print names of generated files part of the compilation. `--listFiles` | `boolean` | `false` | Print names of files part of the compilation. `--locale` | `string` | *(platform specific)* | The locale to use to show error messages, e.g. en-us. `--mapRoot` | `string` | `null` | 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. `--module`
`-m` | `string` | `(target === "ES6" ? "ES6" : "CommonJS")` | Specify module code generation: `'none'`, `'commonjs'`, `'amd'`, `'system'`, `'umd'`, `'es6'`, or `'es2015'`.
► Only `'amd'` and `'system'` can be used in conjunction with `--outFile`.
► `'es6'` and `'es2015'` values may not be used when targeting ES5 or lower. -`--moduleResolution` | `string` | `"Classic"` | Determine how modules get resolved. Either `'node'` for Node.js/io.js style resolution, or `'classic'` (default). See [Module Resolution documentation](Module Resolution.md) for more details. +`--moduleResolution` | `string` | `"Classic"` | Determine how modules get resolved. Either `'node'` for Node.js/io.js style resolution, or `'classic'`. See [Module Resolution documentation](Module Resolution.md) for more details. `--newLine` | `string` | *(platform specific)* | Use the specified end of line sequence to be used when emitting files: `'crlf'` (windows) or `'lf'` (unix)." `--noEmit` | `boolean` | `false` | Do not emit outputs. `--noEmitHelpers` | `boolean` | `false` | Do not generate custom helper functions like `__extends` in compiled output. @@ -31,29 +35,38 @@ Option | Type | Default `--noFallthroughCasesInSwitch` | `boolean` | `false` | Report errors for fallthrough cases in switch statement. `--noImplicitAny` | `boolean` | `false` | Raise error on expressions and declarations with an implied 'any' type. `--noImplicitReturns` | `boolean` | `false` | Report error when not all code paths in function return a value. +`--noImplicitThis` | `boolean` | `false` | Raise error on `this` expressions with an implied 'any' type. `--noImplicitUseStrict` | `boolean` | `false` | Do not emit `"use strict"` directives in module output. `--noLib` | `boolean` | `false` | Do not include the default library file (lib.d.ts). `--noResolve` | `boolean` | `false` | Do not add triple-slash references or module import targets to the list of compiled files. ~~`--out`~~ | `string` | `null` | DEPRECATED. Use `--outFile` instead. `--outDir` | `string` | `null` | Redirect output structure to the directory. `--outFile` | `string` | `null` | 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. +`paths`[2] | `Object` | | List of path mapping entries for module names to locations relative to the `baseUrl`. See [Module Resolution documentation](./Module Resolution.md#path-mapping) for more details. `--preserveConstEnums` | `boolean` | `false` | 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. `--pretty`[1] | `boolean` | `false` | Stylize errors and messages using color and context. `--project`
`-p` | `string` | `null` | Compile a project given a valid configuration file.
The argument can be an file path to a valid JSON configuration file, or a directory path to a directory containing a `tsconfig.json` file.
See [tsconfig.json](./tsconfig.json.md) documentation for more details. `--reactNamespace` | `string` | `"React"` | Specifies the object invoked for `createElement` and `__spread` when targeting 'react' JSX emit. `--removeComments` | `boolean` | `false` | Remove all comments except copy-right header comments beginning with `/*!` `--rootDir` | `string` | *(common root directory is computed from the list of input files)* | Specifies the root directory of input files. Only use to control the output directory structure with `--outDir`. -`--skipDefaultLibCheck` | `boolean` | `false` | Don't check a user-defined default lib file's valitidy. +`rootDirs`[2] | `string[]`| | List of root folders whose combined content represent the structure of the project at runtime. See [Module Resolution documentation](./Module Resolution.md#virtual-directories-with-rootdirs) for more details. +`--skipLibCheck` | `boolean` | `false` | Don't check a the default library (`lib.d.ts`) file's valitidy. +`--skipDefaultLibCheck` | `boolean` | `false` | Don't check a user-defined default library (`*.d.ts`) file's valitidy. `--sourceMap` | `boolean` | `false` | Generates corresponding '.map' file. `--sourceRoot` | `string` | `null` | 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. +`--strictNullChecks` | `boolean` | `false` | In strict null checking mode, the `null` and `undefined` values are not in the domain of every type and are only assignable to themselves and `any` (the one exception being that `undefined` is also assignable to `void`). `--stripInternal`[1] | `boolean` | `false` | Do not emit declarations for code that has an `/** @internal */` JSDoc annotation. `--suppressExcessPropertyErrors` | `boolean` | `false` | Suppress excess property checks for object literals. `--suppressImplicitAnyIndexErrors` | `boolean` | `false` | Suppress `--noImplicitAny` errors for indexing objects lacking index signatures. See [issue #1232](https://github.com/Microsoft/TypeScript/issues/1232#issuecomment-64510362) for more details. -`--target`
`-t` | `string` | `"ES5"` | Specify ECMAScript target version: `'es3'` (default), `'es5'`, or `'es6'`. +`--target`
`-t` | `string` | `"ES3"` | Specify ECMAScript target version: `'es3'` (default), `'es5'`, or `'es6'`. +`--traceResolution` | `boolean` | `false` | Report module resolution log messages. +`--types` | `string[]`| | List of names of type definitions to include. +`--typeRoots` | `string[]`| | List of folders to include type definitions from. `--version`
`-v` | | | Print the compiler's version. `--watch`
`-w` | | | Run the compiler in watch mode. Watch input files and trigger recompilation on changes. -[1] These options are experimental. +* [1] These options are experimental. +* [2] These options are only allowed in `tsconfig.json`, and not through command-line switches. ## Related diff --git a/pages/Interfaces.md b/pages/Interfaces.md index 12610e672..793a46862 100644 --- a/pages/Interfaces.md +++ b/pages/Interfaces.md @@ -98,6 +98,49 @@ function createSquare(config: SquareConfig): { color: string; area: number } { let mySquare = createSquare({color: "black"}); ``` +# Readonly properties + +Some properties should only be modifiable when an object is first created. +You can specify this by putting `readonly` before the name of the property: + +```ts +interface Point { + readonly x: number; + readonly y: number; +} +``` + +You can construct a `Point` by assigning an object literal. +After the assignment, `x` and `y` can't be changed. + +```ts +let p1: Point = { x: 10, y: 20 }; +p1.x = 5; // error! +``` + +TypeScript comes with a `ReadonlyArray` type that is the same as `Array` with all mutating methods removed, so you can make sure you don't change your arrays after creation: + +```ts +let a: number[] = [1, 2, 3, 4]; +let ro: ReadonlyArray = a; +ro[0] = 12; // error! +ro.push(5); // error! +ro.length = 100; // error! +a = ro; // error! +``` + +On the last line of the snippet you can see that even assigning the entire `ReadonlyArray` back to a normal array is illegal. +You can still override it with a type assertion, though: + +```ts +a = ro as number[]; +``` + +## `readonly` vs `const` + +The easiest way to remember whether to use readonly or const is to ask whether you're using it on a variable or a property. +Variables use `const` whereas properties use `readonly`. + # Excess Property Checks In our first example using interfaces, TypeScript let us pass `{ size: number; label: string; }` to something that only expected a `{ label: string; }`. @@ -282,6 +325,18 @@ interface NumberDictionary { } ``` +Finally, you can make index signatures readonly in order to prevent assignment to their indices: + +```ts +interface ReadonlyStringArray { + readonly [index: number]: string; +} +let myArray: ReadonlyStringArray = ["Alice", "Bob"]; +myArray[2] = "Mallory"; // error! +``` + +You can't set `myArray[2]` because the index signature is readonly. + # Class Types ## Implementing an interface diff --git a/pages/Module Resolution.md b/pages/Module Resolution.md index d537ff1c4..7bfd61c9e 100644 --- a/pages/Module Resolution.md +++ b/pages/Module Resolution.md @@ -38,6 +38,37 @@ Some examples include: A relative import is resolved relative to the importing file and *cannot* resolve to an ambient module declaration. You should use relative imports for your own modules that are guaranteed to maintain their relative location at runtime. +A non-relative import can be resolved relative to `baseUrl`, or through path mapping, which we'll cover below. +They can also resolve to [ambient module declarations](./Modules.md#ambient-modules). +Use non-relative paths when importing any of your external dependnecies. + +## Wildcard module declarations + +Some module loaders such as [SystemJS](https://github.com/systemjs/systemjs/blob/master/docs/overview.md#plugin-syntax) +and [AMD](https://github.com/amdjs/amdjs-api/blob/master/LoaderPlugins.md) allow non-JavaScript content to be imported. +These typically use a prefix or suffix to indicate the special loading semantics. +Wildcard module declarations can be used to cover these cases. + +```ts +declare module "*!text" { + const content: string; + export default content; +} +// Some do it the other way around. +declare module "json!*" { + const value: any; + export default value; +} +``` + +Now you can import things that match `"*!text"` or `"json!*"`. + +```ts +import fileContent from "./xyz.txt!text"; +import data from "json!http://example.com/data.json"; +console.log(data, fileContent); +``` + ## Module Resolution Strategies There are two possible module resolution strategies: [Node](#node) and [Classic](#classic). @@ -167,6 +198,214 @@ So `import { b } from "moduleB"` in source file `/src/moduleA.ts` would result i Don't be intimidated by the number of steps here - TypeScript is still only jumping up directories twice at steps (8) and (15). This is really no more complex than what Node.js itself is doing. +## Additional module resolution flags + +A project source layout sometimes does not match that of the output. +Usually a set of build steps result in generating the final output. +These include compiling `.ts` files into `.js`, and copying dependencies from different source locations to a single output location. +The net result is that modules at runtime may have different names than the source files containing their definitions. +Or module paths in the final output may not match their corresponding source file paths at compile time. + +The TypeScript compiler has a set of additional flags to *inform* the compiler of transformations that are expected to happen to the sources to generate the final output. + +It is important to note that the compiler will *not* perform any of these transformations; +it just uses these pieces of information to guide the process of resolving a module import to its definition file. + +### Base URL + +Using a `baseUrl` is a common practice in applications using AMD module loaders where modules are "deployed" to a single folder at run-time. +The sources of these modules can live in different directories, but a build script will put them all together. + +Setting `baseUrl` informs the compiler where to find modules. +All module imports with non-relative names are assumed to be relative to the `baseUrl`. + +Value of *baseUrl* is determined as either: + +* value of *baseUrl* command line argument (if given path is relative, it is computed based on current directory) +* value of *baseUrl* property in 'tsconfig.json' (if given path is relative, it is computed based on the location of 'tsconfig.json') + +Note that relative module imports are not impacted by setting the baseUrl, as they are always resolved relative to their importing files. + +You can find more documentation on baseUrl in [RequireJS](http://requirejs.org/docs/api.html#config-baseUrl) and [SystemJS](https://github.com/systemjs/systemjs/blob/master/docs/overview.md#baseurl) documentation. + +### Path mapping + +Sometimes modules are not directly located under *baseUrl*. +For instance, an import to a module `"jquery"` would be translated at runtime to `"node_modules\jquery\dist\jquery.slim.min.js"`. +Loaders use a mapping configuration to map module names to files at run-time, see [RequireJs documentation](http://requirejs.org/docs/api.html#config-paths) and [SystemJS documentation](https://github.com/systemjs/systemjs/blob/master/docs/overview.md#map-config). + +The TypeScript compiler supports the declaration of such mappings using `"paths"` property in `tsconfig.json` files. +Here is an example for how to specify the `"paths"` property for `jquery`. + +```json +{ + "compilerOptions": { + "paths": { + "jquery": ["node_modules/jquery/dist/jquery.d.ts"] + } +} +``` + +Using `"paths"` also allow for more sophisticated mappings including multiple fall back locations. +Consider a project configuration where only some modules are available in one location, and the rest are in another. +A build step would put them all together in one place. +The project layout may look like: + +```tree +projectRoot +├── folder1 +│ ├── file1.ts (imports 'folder1/file2' and 'folder2/file3') +│ └── file2.ts +├── generated +│ ├── folder1 +│ └── folder2 +│ └── file3.ts +└── tsconfig.json +``` + +The corresponding `tsconfig.json` would look like: + +```json +{ + "compilerOptions": { + "baseUrl": ".", + "paths": { + "*": [ + "*", + "generated/*" + ] + } + } +} +``` + +This tells the compiler for any module import that matches the pattern `"*"` (i.e. all values), to look in two locations: + + 1. `"*"`: meaning the same name unchanged, so map `` => `\` + 2. `"generated\*"` meaning the module name with an appended prefix "generated", so map `` => `\generated\` + +Following this logic, the compiler will attempt to resolve the two imports as such: + +* import 'folder1/file2' + 1. pattern '*' is matched and wildcard captures the whole module name + 2. try first substitution in the list: '*' -> `folder1/file2` + 3. result of substitution is relative name - combine it with *baseUrl* -> `projectRoot/folder1/file2.ts`. + 4. File exists. Done. +* import 'folder2/file3' + 1. pattern '*' is matched and wildcard captures the whole module name + 2. try first substitution in the list: '*' -> `folder2/file3` + 3. result of substitution is relative name - combine it with *baseUrl* -> `projectRoot/folder2/file3.ts`. + 4. File does not exist, move to the second substitution + 5. second substitution 'generated/*' -> `generated/folder2/file3` + 6. result of substitution is relative name - combine it with *baseUrl* -> `projectRoot/generated/folder2/file3.ts`. + 7. File exists. Done. + +### Virtual Directories with `rootDirs` + +Sometimes the project sources from multiple directories at compile time are all combined to generate a single output directory. +This can be viewed as a set of source directories create a "virtual" directory. + +Using 'rootDirs', you can inform the compiler of the *roots* making up this "virtual" directory; +and thus the compiler can resolve relative modules imports within these "virtual" directories *as if* were merged together in one directory. + +For example consider this project structure: + +```tree + src + └── views + └── view1.ts (imports './template1') + └── view2.ts + + generated + └── templates + └── views + └── template1.ts (imports './view2') +``` + +Files in `src/views` are user code for some UI controls. +Files in `generated/templates` are UI template binding code auto-generated by a template generator as part of the build. +A build step will copy the files in `/src/views` and `/generated/templates/views` to the same directory in the output. +At run-time, a view can expect its template to exist next to it, and thus should import it using a relative name as `"./template"`. + +To specify this relationship to the compiler, use`"rootDirs"`. +`"rootDirs"` specify a list of *roots* whose contents are expected to merge at run-time. +So following our example, the `tsconfig.json` file should look like: + +```json +{ + "compilerOptions": { + "rootDirs": [ + "src/views", + "generated/templates/views" + ] + } +} +``` + +Every time the compiler sees a relative module import in a subfolder of one of the `rootDirs`, it will attempt to look for this import in each of the entries of `rootDirs`. + +## Tracing module resolution + +As discussed earlier, the compiler can visit files outside the current folder when resolving a module. +This can be hard when diagnosing why a module is not resolved, or is resolved to an incorrect definition. +Enabling the compiler module resolution tracing using `--traceResolution` provides insight in what happened during the module resolution process. + +Let's say we have a sample application that uses the `typescript` module. +`app.ts` has an import like `import * as ts from "typescript"`. + +```tree +│ tsconfig.json +├───node_modules +│ └───typescript +│ └───lib +│ typescript.d.ts +└───src + app.ts +``` + +Invoking the compiler with `--traceResolution` + +```shell +tsc --traceResolution +``` + +Results in an output as such: + +```txt +======== Resolving module 'typescript' from 'src/app.ts'. ======== +Module resolution kind is not specified, using 'NodeJs'. +Loading module 'typescript' from 'node_modules' folder. +File 'src/node_modules/typescript.ts' does not exist. +File 'src/node_modules/typescript.tsx' does not exist. +File 'src/node_modules/typescript.d.ts' does not exist. +File 'src/node_modules/typescript/package.json' does not exist. +File 'node_modules/typescript.ts' does not exist. +File 'node_modules/typescript.tsx' does not exist. +File 'node_modules/typescript.d.ts' does not exist. +Found 'package.json' at 'node_modules/typescript/package.json'. +'package.json' has 'typings' field './lib/typescript.d.ts' that references 'node_modules/typescript/lib/typescript.d.ts'. +File 'node_modules/typescript/lib/typescript.d.ts' exist - use it as a module resolution result. +======== Module name 'typescript' was successfully resolved to 'node_modules/typescript/lib/typescript.d.ts'. ======== +``` + +#### Things to look out for + +* Name and location of the import + + > ======== Resolving module **'typescript'** from **'src/app.ts'**. ======== + +* The strategy the compiler is following + + > Module resolution kind is not specified, using **'NodeJs'**. + +* Loading of typings from npm packages + + > 'package.json' has **'typings'** field './lib/typescript.d.ts' that references 'node_modules/typescript/lib/typescript.d.ts'. + +* Final result + + > ======== Module name 'typescript' was **successfully resolved** to 'node_modules/typescript/lib/typescript.d.ts'. ======== + ## Using `--noResolve` Normally the compiler will attempt to resolve all module imports before it starts the compilation process. diff --git a/pages/Modules.md b/pages/Modules.md index 9689f8b4c..8dae94f4c 100644 --- a/pages/Modules.md +++ b/pages/Modules.md @@ -500,6 +500,48 @@ import * as URL from "url"; let myUrl = URL.parse("http://www.typescriptlang.org"); ``` +### Shorthand ambient modules + +If you don't want to take the time to write out declarations before using a new module, you can use a shorthand declaration to get started quickly. + +##### declarations.d.ts + +```ts +declare module "hot-new-module"; +``` + +All imports from a shorthand module will have the `any` type. + +```ts +import x, {y} from "hot-new-module"; +x(y); +``` + +### UMD modules + +Some libraries can be used either through imports or through globals. + +##### math-lib.d.ts + +```ts +export const isPrime(x: number): boolean;' +export as namespace mathLib; +``` + +The library can then be used as an import within modules: + +```ts +import { isPrime } from "math-lib"; +isPrime(2); +mathLib.isPrime(2); // ERROR: can't use the global definition from inside a module +``` + +It can also be used as a global variable, but only inside of a script: + +```ts +mathLib.isPrime(2); +``` + # Guidance for structuring modules ## Export as close to top-level as possible diff --git a/pages/Variable Declarations.md b/pages/Variable Declarations.md index aa3f63895..8f3c2bc81 100644 --- a/pages/Variable Declarations.md +++ b/pages/Variable Declarations.md @@ -417,6 +417,8 @@ kitty.numLives--; ``` Unless you take specific measures to avoid it, the internal state of a `const` variable is still modifiable. +Fortunately, TypeScript allows you to specify that members of an object are `readonly`. +The [chapter on Interfaces](./Interfaces.md) has the details. # `let` vs. `const` diff --git a/pages/Writing Declaration Files.md b/pages/Writing Declaration Files.md index d3a75da7a..4d6a1dd59 100644 --- a/pages/Writing Declaration Files.md +++ b/pages/Writing Declaration Files.md @@ -174,6 +174,10 @@ declare var widget: WidgetFactory; ## Global / External-agnostic Libraries +These libraries can be used as either globals or imports. +In a module file (one with any imports/exports), using these as globals is not allowed. +These are also known as [UMD](https://github.com/umdjs/umd) modules. + #### Usage ```ts @@ -187,13 +191,8 @@ zoo.open(); #### Typing ```ts -declare namespace zoo { - function open(): void; -} - -declare module "zoo" { - export = zoo; -} +export function open(): void; +export as namespace zoo; ``` ## Single Complex Object in Modules