官术网_书友最值得收藏!

Types in TypeScript

Working with TypeScript or any other coding language means working with data, and such data can represent different sorts of content that are called types. Types are used to represent the fact that such data can be a text string, an integer value, or an array of these value types, among others. You may have already met types in JavaScript since we have always been working implicitly with them but in a flexible manner. This also means that any given variable could assume (or return, in the case of functions) any value. Sometimes, this leads to errors and exceptions in our code because of type collisions between what our code returned and what we expected it to return type-wise. We can enforce this flexibility using any type, as we will see later in this chapter. However, statically typing our variables gives our IDE and us a good picture of what kind of data we are supposed to find in each instance of code. It becomes an invaluable way to help debug our applications at compile time before it is too late.

String

One of the most widely used primitive types is string, which populates a variable with a piece of text:

var brand: string = 'Chevrolet';

Check out the type definition next to the variable name, which is separated by a colon. This is how we annotate types in TypeScript. We can use either single or double quotes for the value of a string. Feel free to choose either and stick with it within your team. We can define multiline text strings with support for text interpolation with placeholder variables by using backticks:

var brand: string = 'Chevrolet';

var message: string = `Today it's a happy day! I just bought a new ${brand} car`;

In this case, any variables that we may use inside the multiline text must be surrounded by the curly braces of the placeholder ${}.

Declaring variables

TypeScript, as a superset of JavaScript, supports expressive declaration nouns such as let, which denotes that the scope of the variable is the nearest enclosing block (either a function, for loop, or any enclosing statement). On the other hand, const indicates that the value of the declared variable has the same type or value once set.

The let keyword

Traditionally, developers have been using var to declare objects, variables, and other artifacts, but this is discouraged when you start using ES6 or TypeScript. The reason for this is that ES5 only has a function scope; that is, a variable is unique within the context of a function, like so:

function test() {

    var a;

}

There can be no other a variable in this function. If you do declare one, then you effectively redefine it. However, there are cases in which scoping is not applied, such as in for loops. In Java, you would write the following and ensure that a variable will never leak outside of the for loop:

var i = 3;

for (var i = 0; i < 10; i++) {

}

That is, the i variable outside of the for loop will not affect the i variable inside it; they would have a separate scope. But this is not the case with ES5. Thus, ES6 introduced a new feature to fix this flaw, called the let keyword. Consider the following piece of code:

let i = 3;

for (let i = 0; i < 10; i++) {

}

TypeScript compiles it and generates the following JavaScript code:

var i = 3;

for (var i_1 = 0; i_1 < 10; i_1++) {

}

It essentially renames the variable within the for loop so that a name collision doesn't happen. So, remember, no more var; use the let keyword wherever possible.

The const keyword

The const keyword is a way to indicate that a variable should never change. As a code base grows, changes may happen by mistake, and such a mistake might be costly. The const keyword can prevent these types of mistakes through compile-time support. Consider the following code snippet:

const PI = 3.14;

PI = 3;

When the compiler tries to run it, it displays the following error message:

Cannot assign to 'PI' because it is a constant

Notice that this works only at the top level. You need to be aware of this if you declare objects as constants, like so:

const obj = {

    a: 3

};

obj.a = 4; 

Declaring obj as a constant does not freeze the entire object from being edited, but rather what it points to. So, the preceding code is valid.

In the following example, we're actively changing the reference of obj, not one of its properties. Therefore, it is not allowed, and we get the same compiler error that we got previously:

obj = {};

Important Note

const versus let: Prefer to use the const keyword over let when you are sure that the properties of an object will not change during its lifetime. This prevents the object from accidentally changing at runtime and enforces data immutability, a hot topic in Angular applications.

Number

number is probably the other most widespread primitive data type, along with string and boolean:

const age: number = 7;

const height: number = 5.6;

It defines a floating-point number, as well as hexadecimal, decimal, binary, and octal literals.

Boolean

The boolean type defines a variable that can have a value of either true or false:

const isZeroGreaterThanOne: boolean = false;

The result of the variable represents the fulfillment of a boolean condition.

Array

Handling exceptions that arise from errors such as assigning wrong member types in a list can now be easily avoided with the array type, where it defines a list of items that contain certain types only. The syntax requires the postfix [] in the type annotation, as follows:

const brand: string[] = ['Chevrolet', 'Ford', 'General Motors'];

const ages: number[] = [8, 5, 12, 3, 1];

If we try to add a new item to the ages array with a type other than number, the runtime type checker will complain, making sure our typed members remain consistent and that our code is error-free.

Dynamic typing with any type

Sometimes, it is hard to infer the data type out of the information we have at any given point, especially when we are porting legacy code to TypeScript or integrating loosely typed third-party libraries and modules. TypeScript supplies us with a convenient type for these cases. The any type is compatible with all the other existing types, so we can type any data value with it and assign any value to it later:

let distance: any;

distance = '1000km';

distance = 1000;

const distances: any[] = ['1000km', 1000];

However, this great power comes with great responsibility. If we bypass the convenience of static type checking, we are opening the door to type errors when piping data through our modules. It is up to us to ensure type safety throughout our application.

Important Note

The null and undefined literals require special treatment. In a nutshell, they are typed under the any type, which makes it possible to assign these literals to any other variable, regardless of its original type.

Custom types

In TypeScript, you can come up with your own type if you need to by using the type keyword in the following way:

type Animal = 'Cheetah' | 'Lion';

It is essentially a type with a finite number of allowed values. Let's create a variable from this type:

const animal: Animal = 'Cheetah';

This is perfectly valid as Cheetah is one of the allowed values and works as intended.

The interesting part happens when we give our variable a value it does not expect:

const animal: Animal = 'Turtle';

This results in the following compiler error:

Type '"Turtle"' is not assignable to type 'Animal'.

Enum

The enum type is a set of unique numeric values that we can represent by assigning user-friendly names to each of them. Its use goes beyond assigning an alias to a number. We can use it as a way to list the different variations that a specific type can assume, in a convenient and recognizable way. It is defined using the enum keyword and begins numbering members, starting at 0, unless explicit numeric values are assigned to them:

enum Brands { Chevrolet, Cadillac, Ford, Buick, Chrysler, Dodge };

const myCar: Brands = Brands.Cadillac;

Inspecting the value of myCar returns 1 (which is the index held by Cadillac). As we mentioned already, we can assign custom numeric values in enum:

enum BrandsReduced { Tesla = 1, GMC, Jeep };

const myTruck: BrandsReduced = BrandsReduced.GMC;

Inspecting myTruck yields 2, since the first enumerated value, Tesla, was set to 1 already. We can extend value assignation to all the enum members as long as such values are integers:

enum StackingIndex {

    None = 0,

    Dropdown = 1000,

    Overlay = 2000,

    Modal = 3000

};

const mySelectBoxStacking: StackingIndex = StackingIndex.Dropdown;

One last point worth mentioning is the possibility to look up the enum member mapped to a given numeric value:

enum Brands { Chevrolet, Cadillac, Ford, Buick, Chrysler, Dodge };

const myCarBrandName: string = Brands[1];

It should also be mentioned that from TypeScript 2.4 and onward, it is possible to assign string values to enums. This is something that is preferred in Angular projects because of its extended support in template files.

Void

The void type represents the absence of a type, and its use is constrained to annotating functions that do not return an actual value:

function test(): void {

    const a = 0;

}

Therefore, there is no return type in function either.

Type inference

Typing is optional since TypeScript is smart enough to infer the data types of variables and function return values out of context with a certain level of accuracy. When this is not possible, it will assign the dynamic any type to the loosely-typed data at the cost of reducing type checking to a bare minimum. The following is an example of this:

const brand = 'Chevrolet';

This holds the same effect; that is, it leads to a compilation error if you try to assign a non-compatible data type to it.

主站蜘蛛池模板: 科尔| 凤城市| 曲阜市| 朝阳市| 泸西县| 营口市| 上栗县| 英山县| 桐梓县| 新疆| 织金县| 伊川县| 左贡县| 乌什县| 类乌齐县| 庆阳市| 昭苏县| 克什克腾旗| 红安县| 通许县| 昌图县| 宝坻区| 凤山市| 山东| 临西县| 茶陵县| 孝义市| 阳东县| 化德县| 兴隆县| 梅州市| 姜堰市| 仪征市| 冷水江市| 方正县| 彭州市| 南和县| 济阳县| 哈巴河县| 全椒县| 漳浦县|