⬆️ ⬇️

TypeScript 3.0

TypeScript 3.0! Yes, it came out, and there are really a lot of innovations in it. Under the cat you will find a detailed description of all the latest versions of the latest version, including the build mode, a new unknown type, significant changes in the API, performance improvements and much more. Join now!







TypeScript 3.0 released! A new milestone in the development of TypeScript, an assistant to all users of JavaScript, has begun.

')

If you are not familiar with TypeScript yet, it’s not too late to find out about it now! TypeScript is a JavaScript extension developed for use in the modern version of this static type language. The TypeScript compiler reads TypeScript code containing, in particular, type declarations and annotations, and provides clean, easy to read JavaScript code in which these constructs are converted and deleted. The resulting code runs in any runtime environment that conforms to the ECMAScript standard, for example in your favorite browser or on the Node.js server platform.



Using such an environment means that the code will be analyzed for errors or typos before it is launched by users, but its benefits are not limited to this. With all this information and analysis results, TimeScript improves usability by providing automatic code completion and navigation tools such as Find all References, Go to Definition, and Rename in your favorite editor. .



To get started with the language and get more information, follow the link . If you want to try TypeScript 3.0 right now, you can download it from NuGet or via npm by entering the command



npm install -g typescript 


In addition, support is available in the following editors:





Other editors are updated according to their own graphics, but soon they will all have excellent TypeScript support.



Review Version 3.0



After TypeScript 2.0, we made a brief overview of the contributions of previous versions to its current state. Between the releases of TypeScript 1.0 and 2.0, the language includes union types, type conditions (type guards), support for the current ECMAScript standard, type aliases, JSX support, and literal and polymorphic types this . If we also include the introduced non-null TypeScript 2.0 types, control flow analysis, support for tagged unions, this types and a simplified model for obtaining .d.ts files, then we can say that this period fully defined the basics TypeScript works.



So what has been done since then? What brought us to TypeScript 3.0, in addition to the new features of the ECMAScript standard like async / async / await asynchronous functions, generators and the extension / rest (rest / spread) operator?



TypeScript 2.1 was a fundamental release in which a static model of metaprogramming in JavaScript was introduced. Key request ( keyof ), index access ( T[K] ) and types of associated objects ( { [K in keyof T]: } T[K]} ) - here is a list of tools that were used to more effectively model the React, Ember libraries, Lodash and others.



In TypeScript 2.2 and 2.3 releases, there is support for the mixin class templates, object type (representing an object that is not a primitive), and default values ​​for generic types. These features have been used in a number of projects, such as Angular Material and Polymer. In addition, TypeScript 2.3 introduced the possibility of detailed control of this types, which allows the language to work well with libraries such as Vue, and the checkJs flag was checkJs , allowing you to check types in JavaScript files.



In the TypeScript 2.4 and 2.6 releases, the story continues to increase the severity of function type checking associated with some of the oldest reviews about our type system. The --strictFunctionTypes flag was introduced, forcing the contravariance of parameters. In release 2.7, the trend towards rigor has been preserved and has been expressed in testing in classes using the --strictPropertyInitialization flag.



In TypeScript 2.8, conditional types are introduced, a powerful tool for static expression of types-based solutions, and release 2.9 summarizes the keyof operator and simplifies import for types.



And that brings us to TypeScript 3.0! Despite the new integer number in the issue, little has changed in release 3.0 (which implies a very easy update). It introduces a new, flexible and scalable way of structuring projects, powerful new support for working with parameter lists, new types for providing explicit checks, improved JSX support, significantly more user-friendly error diagnostics, and much more.



What's new?





Links to projects



Quite often, building a library or application requires several steps. Suppose your code base contains the src and test directories. Suppose you have a client folder where the client-side code of the application is stored, and a server folder containing the server-side code on the Node.js platform, and each of them borrows a part of the code from the shared folder. Perhaps you use the so-called “single repository” and have many projects that are complexly dependent on each other.



One of the most important functions that we worked on with the release of TypeScript 3.0, called "links to the project", and it is designed to simplify the work with such scripts.



Thanks to links to a project, some TypeScript projects may depend on others. In particular, tsconfig.json files tsconfig.json allowed to reference other tsconfig.json files. Defining these dependencies makes it easy to divide the code into smaller projects, because the TypeScript compiler (and its tools) can understand the build order and the structure of the output. This means that the assembly is faster and is performed incrementally (step by step), transparent navigation, editing and refactoring on various projects are supported. Since TypeScript 3.0 lays the foundation for the project and provides an API, any build tool must be able to provide this.



What does this look like?



As a simple example, here is the tsconfig.json file containing references to projects.



 // ./src/bar/tsconfig.json { "compilerOptions": { // Needed for project references. "composite": true, "declaration": true, // Other options... "outDir": "../../lib/bar", "strict": true, "module": "esnext", "moduleResolution": "node", }, "references": [ { "path": "../foo" } ] } 


It has two new fields: composite and references .



The references field simply points to other tsconfig.json files (or the folders in which they are contained). Each link here is just an object with a path field ("path") and indicates to the TypeScript compiler that to build this project you first need to build another project to which it refers.



Apparently, the field composite has the same importance. The composite field ensures that certain parameters will be included that allow any project that depends on a given one to refer to it and to include it in an incremental build. Intellectual and incremental build is important because one of the main reasons why you can abandon the project is assembly speed.



For example, if a front-end project is dependent on a shared project, and a shared - on a core, then our APIs related to project references will help identify changes in the core, but reassemble only the shared ones if the types produced by the project core (i.e., .d.ts files). This means that a change in core does not entail a global reassembly of all projects. For this reason, setting the composite flag also gives rise to the setting and the declaration flag.



--Build mode



In TypeScript 3.0, a set of APIs will appear for referencing projects so that other tools can provide this fast incremental build method. In particular, in the gulp-typescript plug-in, these APIs are already used! Thus, later references to projects will be integrated with your chosen orchestra compilers.



However, for many simple applications and libraries, it is advisable not to use external tools. That is why the tbu command now sets the new flag - --build .



The tsc --build (or its pseudonym, tsc -b ) takes a set of projects and builds them, as well as build dependent projects. When using the new build mode, first, the - build flag must be set, and it can be combined with some other flags:



Output structure management



One subtle, but incredibly useful advantage of references to projects is the logical ability to match input files with the corresponding output.



If you have ever tried to separate the client and server parts of the application, then you might encounter problems managing the output structure.



For example, if both the client / index.ts and server / index.ts files refer to shared / index.ts for the following projects:







... then when we try to build client and server projects we get ...







…but not…







Note that after the build, we received copies of the shared folder in both the client and server. We spent too much time on the shared shared build and added an undesirable level of nesting in lib / client / client and lib / server / server.



The problem is that TypeScript is eagerly looking for .ts files and trying to include them in this compilation. Ideally, TypeScript should understand that these files should not be part of the assembly in the same compilation, and instead refer to the .d.ts files for information about the types.



Creating a tsconfig.json file for shared results in exactly this result. It signals the TypeScript compiler:



  1. that a shared project should be built independently
  2. and that when importing from ../shared we should look for .d.ts files in its output directory.


This allows you to avoid running a double build, as well as accidental inclusion of the entire contents of the shared.



Future plans



To gain a deeper understanding of the project links and the possibilities of using them, read about them in more detail in the tracker of this release . In the near future we will prepare documentation for links to projects and build mode.



We want authors of other programming tools to maintain links to projects and continue to improve the editing environment with regard to this function. We intend to ensure that working with links to projects goes as smoothly as developing code with a single tsconfig.json file. If you end up using links to projects, we will be grateful for any feedback.



Extract and distribute parameter lists using tuples



We often take this for granted, but JavaScript allows us to treat parameter lists as first-class values ​​— using either arguments or rest parameters (for example, ... rest).



 function call(fn, ...args) { return fn(...args); } 


Note that call works for functions with any number of parameters. Unlike other languages, JavaScript does not force us to define call0, call1, call2, etc., as follows:



 function call0(fn) { return fn(); } function call1(fn, param1) { return fn(param1); } function call2(fn, param1, param2) { return fn(param1, param2); } function call3(fn, param1, param2, param3) { return fn(param1, param2, param3); } 


Unfortunately, for some time there was no good way to express it in TypeScript without declaring a finite number of overloads:



 // TODO (billg): 5 overloads should *probably* be enough for anybody? function call<T1, T2, T3, T4, R>(fn: (param1: T1, param2: T2, param3: T3, param4: T4) => R, param1: T1, param2: T2, param3: T3, param4: T4): R function call<T1, T2, T3, R>(fn: (param1: T1, param2: T2, param3: T3) => R, param1: T1, param2: T2, param3: T3): R function call<T1, T2, R>(fn: (param1: T1, param2: T2) => R, param1: T1, param2: T2): R function call<T1, R>(fn: (param1: T1) => R, param1: T1): R; function call<R>(fn: () => R, param1: T1): R; function call(fn: (...args: any[]) => any, ...args: any[]) { return fn(...args); } 


Phew! Another fatal case with a thousand overloads! Or at least as much of the overload as required by users.



TypeScript 3.0 allows you to better model such scripts, since now parameters of the rest type can be universal, and their type is defined as a tuple. Instead of declaring each of these overloads, we say that the rest parameter ... args from the fn function should be a type parameter that expands the array, and then reuse it for the ... args parameter that the call function passes:



 function call<TS extends any[], R>(fn: (...args: TS) => R, ...args: TS): R { return fn(...args); } 


When we call the call function, TypeScript tries to extract the parameter list from what we pass to fn, and turn it into a tuple:



 function foo(x: number, y: string): string { return (x + y).toLowerCase(); } // The `TS` type parameter is inferred as `[number, string]` call(foo, 100, "hello"); 


When TypeScript defines TS as [number, string], and we end up using TS for the rest parameter of the call function, an instance of the function looks like this:



 function call(fn: (...args: [number, string]) => string, ...args: [number, string]): string 


And in TypeScript 3.0, when using a tuple in the rest, the parameter is minimized to the rest of the parameter list! The above copy is reduced to simple parameters without tuples:



 function call(fn: (arg1: number, arg2: string) => string, arg1: number, arg2: string): string 


So, in addition to catching type conversion errors on passing invalid arguments:



 function call<TS extends any[], R>(fn: (...args: TS) => R, ...args: TS): R { return fn(...args); } call((x: number, y: string) => y, "hello", "world"); // ~~~~~~~ // Error! `string` isn't assignable to `number`! 


... and type definitions from other arguments:



 call((x, y) => { /* .... */ }, "hello", 100); // ^ ^ // `x` and `y` have their types inferred as `string` and `number` respectively. 


... we can also see the tuple types that these functions define externally:



 function tuple<TS extends any[]>(...xs: TS): TS { return xs; } let x = tuple(1, 2, "hello"); // has type `[number, number, string]` 


But pay attention to one nuance. To do all this work, we had to expand the possibilities of tuples ...



New features of tuple types



In order to model the list of parameters in the form of a tuple (as we have just discussed), we had to rethink the tuple types for a bit. Prior to the release of TypeScript 3.0, the best of what was allowed to be modeled using tuples was the order and length of the parameter set.



However, parameter lists are not just ordered type lists. For example, parameters at the end may be optional:



 // Both `y` and `z` are optional here. function foo(x: boolean, y = 100, z?: string) { // ... } foo(true); foo(true, undefined, "hello"); foo(true, 200); 


The last parameter may be a rest parameter.



 // `rest` accepts any number of strings - even none! function foo(...rest: string[]) { // ... } foo(); foo("hello"); foo("hello", "world"); 


And finally, there is one rather interesting property of parameter lists - they can be empty:



 // Accepts no parameters. function foo() { // ... } foo(); 


Therefore, in order for tuples to match the parameter lists, we needed to model each of these scenarios.



First, there are now optional elements at the end of the tuples:



 /** * 2D, or potentially 3D, coordinate. */ type Coordinate = [number, number, number?]; 


The Coordinate type creates a tuple with an optional property named 2 — an element with index 2 may not be defined! Interestingly, since tuples use numeric literal types for their length property (length), the length property of the Coodinate tuple is type 2 | 3



Secondly, the rest element may now be present at the end of the tuple.



 type OneNumberAndSomeStrings = [number, ...string[]]; 


Thanks to the rest elements, the tuples exhibit a very interesting behavior of "unbounded from the end." In the example above, the type OneNumberAndSomeStrings is required for the type of its first property to be number, and one or more properties of type string are allowed. Indexing this type of tuple with an arbitrary number number returns the type string | number because the index value is unknown. Similarly, since the length of the tuple is unknown, the value of the length property is just a number.



It should be noted that in the absence of other elements, the rest element in a tuple is identical to itself:



 type Foo = [...number[]]; // Equivalent to `number[]`. 


Finally, tuples can now be empty! Although it is not very useful when used outside parameter lists, an empty tuple type can be defined as []:



 type EmptyTuple = []; 


As you would expect, the empty tuple has a length property of 0, and indexing with number returns the type never.



Improved error diagnosis and user environment



Over time, we receive more and more requests from members of our community to improve error messages. Although this work is far from complete, we heard you and made a number of improvements in TypeScript 3.0.



Related error ranges



In part, the goal of a good error message is to indicate to the user also the way to correct it, or, first of all, to make it clear why this message appeared. In most cases, it contains a lot of information or indicates several reasons for its occurrence. From an analysis of these reasons, we can conclude that errors flow from different parts of the code.



Related error ranges are a new way to provide this information to users. In TypeScript 3.0, error messages can generate messages elsewhere in the code so that users can find out the cause and effect of the error.







In a sense, the associated error messages can not only give an explanation to the user, but also indicate the path to the place where everything went wrong.







These intervals will also appear in terminal mode when you run the tsc command with the --pretty mode enabled, although we are still working on improving the user interface and will take into account your feedback!



Improved diagnostics and error handling



In preparing the TypeScript 2.9 release, we began to pay more attention to error messages, and in Release 3.0, we really tried to solve the main tasks that would allow us to perform an intelligent, clear and accurate error diagnosis. This includes, in particular, the selection of appropriate types in case of inconsistencies in the types of union and output directly to the source of error for certain types of messages.



We believe that our efforts have been justified, and as a result you will receive shorter and clearer error messages.











Type unknown



The type any (any) is a type in TypeScript, suitable for anything. Since it covers the types of all possible values, it does not force us to do any checks before we try to call these values, construct them, or access their properties. It also allows you to assign any type values ​​to variables that expect values ​​of any other type.



This feature is generally useful, but cannot provide sufficient rigor.



 let foo: any = 10; // All of these will throw errors, but TypeScript // won't complain since `foo` has the type `any`. foo.x.prop; foo.y.prop; foo.z.prop; foo(); new foo(); upperCase(foo); foo `hello world!`; function upperCase(x: string) { return x.toUpperCase(); } 


Sometimes in TypeScript I want to describe a type that does not fit to anything. This is useful for the API that wants to signal: "there can be any value here, so you need to do some checking before using it." And users are forced to analyze the returned values ​​for security reasons.



TypeScript 3.0 introduces a new type called unknown, which does just that. any, unknown , , any, unknown . unknown, .



unknown any, foo :



 let foo: unknown = 10; // Since `foo` has type `unknown`, TypeScript // errors on each of these locations. foo.x.prop; foo.y.prop; foo.z.prop; foo(); new foo(); upperCase(foo); foo `hello world!`; function upperCase(x: string) { return x.toUpperCase(); } 


, , , .



 let foo: unknown = 10; function hasXYZ(obj: any): obj is { x: any, y: any, z: any } { return !!obj && typeof obj === "object" && "x" in obj && "y" in obj && "z" in obj } // Using a user-defined type guard... if (hasXYZ(foo)) { // ...we're allowed to access certain properties again. foo.x.prop; foo.y.prop; foo.z.prop; } // We can also just convince TypeScript we know what we're doing // by using a type assertion. upperCase(foo as string); function upperCase(x: string) { return x.toUpperCase(); } 


: , , , {} | null | undefined, unknown , :



 type Arrayify<T> = T extends any ? Array<T> : never; type A = Arrayify<{} | null | undefined>; // null[] | undefined[] | {}[] type B = Arrayify<unknown>; // unknown[] 


defaultProps JSX



: .d.ts React , , .



- TypeScript/JavaScript , , . , . , .



 function loudlyGreet(name = "world") { // Thanks to the default initializer, `name` will always have type `string` internally. // We don't have to check for `undefined` here. console.log("HELLO", name.toUpperCase()); } // Externally, `name` is optional, and we can potentially pass `undefined` or omit it entirely. loudlyGreet(); loudlyGreet(undefined); 


React (props). React , defaultProps, props.



 // Some non-TypeScript JSX file import * as React from "react"; import * as ReactDOM from "react-dom"; export class Greet extends React.Component { render() { const { name } = this.props; return <div>Hello ${name.toUpperCase()}!</div>; } static defaultProps = { name: "world", }; } // Notice no `name` attribute was specified! // vvvvvvvvv const result = ReactDOM.renderToString(<Greet />); console.log(result); 


, <Greet /> name. Greet, name «world», : Hello world!.



, TypeScript , defaultProps - JSX. render:



 export interface Props { name?: string } export class Greet extends React.Component<Props> { render() { const { name } = this.props; // Notice the `!` ------v return <div>Hello ${name!.toUpperCase()}!</div>; } static defaultProps = { name: "world"} } 


, .



TypeScript 3.0 JSX, LibraryManagedAttributes. , , TypeScript, JSX. , , React defaultProps , , propTypes.



 export interface Props { name: string } export class Greet extends React.Component<Props> { render() { const { name } = this.props; return <div>Hello ${name.toUpperCase()}!</div>; } static defaultProps = { name: "world"} } // Type-checks! No type assertions needed! let el = <Greet /> 


, . defaultProps, Partial , - (stateless function components, SFC), defaultProps Partial , . defaultProps (. ) SFC ES2015:



 function Greet({ name = "world" }: Props) { return <div>Hello ${name.toUpperCase()}!</div>; } 


, . TypeScript, .d.ts DefinitelyTyped , , @types/react . DefinitelyTyped, .



/// <reference lib="..." />



, , , (polyfills) — , API , ( .d.ts), API. , TypeScript lib.d.ts , --lib --target. , core-js lib.es2015.d.ts.



TypeScript 3.0 , API, , : /// <reference lib="..." />.



, Promise ES2015



 /// <reference lib="es2015.promise" /> export {}; 


, TypeScript 3.0 , lib.es2015.promise.d.ts, , Promise .





, , TypeScript , . TypeScript JavaScript , Visual Studio, Visual Studio Code TypeScript. , , , Go to Definition (« ») . TypeScript 3.0 .





, , .



 import * as dependency from "./dependency"; // look at all this repetition! dependency.foo(); dependency.bar(); dependency.baz(); 


, , , , .



 import { foo, bar, baz } from "./dependency"; // way lower in the file... foo(); bar(); baz(); 


, , . TypeScript 3.0 , .









TypeScript , JSX:











TypeScript — , .





, API .



, TypeScript 3 , . , API .



unknown —



unknown — , , , .



API





Perspectives



TypeScript . , , , DefinitelyTyped , . , .



, TypeScript ( , ). , , JavaScript. , TypeScript, .



, , , , , Twitter . .



, TypeScript, ! . , , TypeScript , .



!

TypeScript

Source: https://habr.com/ru/post/420761/



All Articles