TypeScript data type, arbitrary value, type inference, union type, interface (Interfaces, optional attribute?:, arbitrary attribute, read-only attribute)

Keywords: Javascript Front-end TypeScript

TypeScript (II) data type, arbitrary value, type inference, joint type, interface (Interfaces, optional attribute?:, arbitrary attribute, read-only attribute)

  • website: https://ts.xcatliu.com/

1. Original data type

There are two types of JavaScript: raw data type( Primitive data types )And Object types.

Raw data types include Boolean, numeric, string, null, undefined, and new types in ES6 Symbol And new types in ES10 BigInt.

This section mainly introduces the application of the first five raw data types in TypeScript.

Boolean value

boolean value is the most basic data type. In TypeScript, boolean is used to define boolean value type:

let isDone: boolean = false;

// Compile passed
// As agreed later, code fragments that do not emphasize compilation errors are compiled by default

Note that the object created using the constructor Boolean is not Boolean:

let createdByNewBoolean: boolean = new Boolean(1);

// Type 'Boolean' is not assignable to type 'boolean'.
//   'boolean' is a primitive, but 'Boolean' is a wrapper object. Prefer using 'boolean' when possible.

In fact, new Boolean() returns a Boolean object:

let createdByNewBoolean: Boolean = new Boolean(1);

Directly calling Boolean can also return a boolean type:

let createdByBoolean: boolean = Boolean(1);

In TypeScript, Boolean is the basic type in JavaScript, and Boolean is the constructor in JavaScript. Other basic types (except null and undefined) are the same and will not be repeated.

numerical value

Use number to define the value type:

let decLiteral: number = 6;
let hexLiteral: number = 0xf00d;
// Binary representation in ES6
let binaryLiteral: number = 0b1010;
// Octal notation in ES6
let octalLiteral: number = 0o744;
let notANumber: number = NaN;
let infinityNumber: number = Infinity;

Compilation result:

var decLiteral = 6;
var hexLiteral = 0xf00d;
// Binary representation in ES6
var binaryLiteral = 10;
// Octal notation in ES6
var octalLiteral = 484;
var notANumber = NaN;
var infinityNumber = Infinity;

Where 0b1010 and 0o744 are Binary and octal representations in ES6 , they are compiled into decimal numbers.

character string

Use string to define string type:

let myName: string = 'Tom';
let myAge: number = 25;

// Template string
let sentence: string = `Hello, my name is ${myName}.
I'll be ${myAge + 1} years old next month.`;

Compilation result:

var myName = 'Tom';
var myAge = 25;
// Template string
var sentence = "Hello, my name is " + myName + ".
I'll be " + (myAge + 1) + " years old next month.";

Where ` ` ` is used to define Template string in ES6 , ${expr} is used to embed an expression in the template string.

Null value

JavaScript does not have the concept of void. In TypeScript, void can be used to represent functions without any return value:

function alertName(): void {
    alert('My name is Tom');
}

It is useless to declare a variable of void type, because you can only assign it to undefined and null (only when -- strictNullChecks is not specified):

let unusable: void = undefined;

Null and Undefined

  • After this article, the strict mode is adopted, which is based on the configuration of strict: true in tsconfig.json
  • This section adopts a non strict mode.
  • let num: number = undefined; // In strict mode, an error will be reported
  • When declaring that the data type of a variable is void, the value of the variable can be undefined or null in non strict mode. In strict mode, the value of a variable can only be undefined.

In TypeScript, you can use null and undefined to define these two raw data types:

let u: undefined = undefined;
let n: null = null;

The difference from void is that undefined and null are subtypes of all types. That is, variables of type undefined can be assigned to variables of type number:

// This will not report an error
let num: number = undefined;
// This will not report an error
let u: undefined;
let num: number = u;

A variable of void type cannot be assigned to a variable of number type:

let u: void;
let num: number = u;

// Type 'void' is not assignable to type 'number'.

reference resources

2. Any value

Any value is used to indicate that assignment to any type is allowed.

What is an arbitrary value type

If it is a common type, it is not allowed to change the type during assignment:

let myFavoriteNumber: string = 'seven';
myFavoriteNumber = 7;

// index.ts(2,1): error TS2322: Type 'number' is not assignable to type 'string'.

However, if it is any type, it is allowed to be assigned to any type.

let myFavoriteNumber: any = 'seven';
myFavoriteNumber = 7;

Properties and methods of arbitrary values

Access to any property on any value is allowed:

let anyThing: any = 'hello';
console.log(anyThing.myName);
console.log(anyThing.myName.firstName);

Any method can also be called:

let anyThing: any = 'Tom';
anyThing.setName('Jerry');
anyThing.setName('Jerry').sayHello();
anyThing.myName.setFirstName('Cat');

It can be considered that after declaring a variable as an arbitrary value, the type of content returned by any operation on it is an arbitrary value.

Variable of undeclared type

If a variable is declared without specifying its type, it will be recognized as any value type:

let something;
something = 'seven';
something = 7;

something.setName('Tom');

Equivalent to

let something: any;
something = 'seven';
something = 7;

something.setName('Tom');

3. Type inference

If no type is explicitly specified, TypeScript infers a type according to the rules of Type Inference.

What is type inference

Although the following code does not specify a type, it will report an error during compilation:

let myFavoriteNumber = 'seven';
myFavoriteNumber = 7;

// index.ts(2,1): error TS2322: Type 'number' is not assignable to type 'string'.

In fact, it is equivalent to:

let myFavoriteNumber: string = 'seven';
myFavoriteNumber = 7;

// index.ts(2,1): error TS2322: Type 'number' is not assignable to type 'string'.

TypeScript will infer a type when there is no explicit specified type, which is type inference.

If there is no assignment at the time of definition, no matter whether there is assignment later, it will be inferred as any type and will not be checked at all:

let myFavoriteNumber;
myFavoriteNumber = 'seven';
myFavoriteNumber = 7;

reference resources

  • Type Inference ([Chinese version]( https://zhongsp.gitbooks.io/typescript-handbook/content/doc/handbook/Type Inference.html))

4. Joint type

Union Types means that the value can be one of a variety of types.

Simple example

let myFavoriteNumber: string | number;
myFavoriteNumber = 'seven';
myFavoriteNumber = 7;
let myFavoriteNumber: string | number;
myFavoriteNumber = true;

// index.ts(2,1): error TS2322: Type 'boolean' is not assignable to type 'string | number'.
//   Type 'boolean' is not assignable to type 'number'.

Union types use | to separate each type.

let myFavoriteNumber: string | number here means that the type of myFavoriteNumber is allowed to be string or number, but it cannot be other types.

Accessing properties or methods of a union type

When TypeScript does not know which type the variable of a union type is, we can only access the properties or methods common to all types of the union type:

function getLength(something: string | number): number {
    return something.length;
}

// index.ts(2,22): error TS2339: Property 'length' does not exist on type 'string | number'.
//   Property 'length' does not exist on type 'number'.

In the above example, length is not a common attribute of string and number, so an error will be reported.

It is OK to access the common properties of string and number:

function getString(something: string | number): string {
    return something.toString();
}

When a variable of joint type is assigned, a type will be inferred according to the rules of type inference:

let myFavoriteNumber: string | number;
myFavoriteNumber = 'seven';
console.log(myFavoriteNumber.length); // 5
myFavoriteNumber = 7;
console.log(myFavoriteNumber.length); // Compile error

// index.ts(5,30): error TS2339: Property 'length' does not exist on type 'number'.

In the above example, the myFavoriteNumber in the second line is inferred as a string, and no error will be reported when accessing its length attribute.

The myFavoriteNumber in the fourth line is inferred as number, and an error is reported when accessing its length attribute.

reference resources

  • Advanced Types # Union Types ([Chinese version]( https://zhongsp.gitbooks.io/typescript-handbook/content/doc/handbook/Advanced Types.html# union type)

5. Object type - Interfaces

In TypeScript, we use Interfaces to define the type of object.

What is an interface

In object-oriented language, Interfaces is a very important concept. It is the abstraction of behavior, and how to act needs to be implement ed by classes.

The interface in TypeScript is a very flexible concept, except that it can be used for Abstract part of the behavior of a class In addition, it is also commonly used to describe the "Shape of the object".

Simple example

interface Person {
    name: string;
    age: number;
}

let tom: Person = {
    name: 'Tom',
    age: 25
};

In the above example, we defined an interface Person, and then defined a variable tom, whose type is Person. In this way, we constrain that the shape of tom must be consistent with the interface Person.

Interfaces are generally capitalized. In some programming languages, it is recommended to prefix the name of the interface with I.

The defined variable has fewer attributes than the interface, which is not allowed:

interface Person {
    name: string;
    age: number;
}

let tom: Person = {
    name: 'Tom'
};

// index.ts(6,5): error TS2322: Type '{ name: string; }' is not assignable to type 'Person'.
//   Property 'age' is missing in type '{ name: string; }'.

More attributes are not allowed:

interface Person {
    name: string;
    age: number;
}

let tom: Person = {
    name: 'Tom',
    age: 25,
    gender: 'male'
};

// index.ts(9,5): error TS2322: Type '{ name: string; age: number; gender: string; }' is not assignable to type 'Person'.
//   Object literal may only specify known properties, and 'gender' does not exist in type 'Person'.

It can be seen that during assignment, the shape of the variable must be consistent with the shape of the interface.

Optional attributes?:

Sometimes we want to not exactly match a shape, so we can use the optional attribute:

interface Person {
    name: string;
    age?: number;
}

let tom: Person = {
    name: 'Tom'
};
interface Person {
    name: string;
    age?: number;
}

let tom: Person = {
    name: 'Tom',
    age: 25
};

The meaning of optional attribute is that the attribute can not exist.

It is still not allowed to add undefined attributes at this time:

interface Person {
    name: string;
    age?: number;
}

let tom: Person = {
    name: 'Tom',
    age: 25,
    gender: 'male'
};

// examples/playground/index.ts(9,5): error TS2322: Type '{ name: string; age: number; gender: string; }' is not assignable to type 'Person'.
//   Object literal may only specify known properties, and 'gender' does not exist in type 'Person'.

Any attribute

Sometimes we want an interface to allow arbitrary attributes. We can use the following methods:

interface Person {
    name: string;
    age?: number;
    [propName: string]: any;
}

let tom: Person = {
    name: 'Tom',
    gender: 'male'
};

Any attribute defined with [propName: string] takes the value of string type.

It should be noted that once any attribute is defined, the types of the determined attribute and optional attribute must be a subset of its types:

interface Person {
    name: string;
    age?: number;
    [propName: string]: string;
}

let tom: Person = {
    name: 'Tom',
    age: 25,
    gender: 'male'
};

// index.ts(3,5): error TS2411: Property 'age' of type 'number' is not assignable to string index type 'string'.
// index.ts(7,5): error TS2322: Type '{ [x: string]: string | number; name: string; age: number; gender: string; }' is not assignable to type 'Person'.
//   Index signatures are incompatible.
//     Type 'string | number' is not assignable to type 'string'.
//       Type 'number' is not assignable to type 'string'.

In the above example, the value of any attribute is allowed to be string, but the value of the optional attribute age is number, which is not a child attribute of string, so an error is reported.

In addition, it can be seen from the error message that the type of {name: 'Tom', age: 25, gender: 'male'} is inferred as {[x: string]: string | number; name: string; age: number; gender: string;}, which is the combination of joint types and interfaces.

Only one arbitrary attribute can be defined in an interface. If there are multiple types of attributes in the interface, you can use the union type in any attribute:

interface Person {
    name: string;
    age?: number;
    [propName: string]: string | number;
}

let tom: Person = {
    name: 'Tom',
    age: 25,
    gender: 'male'
};

Read only attribute

Sometimes we want some fields in the object to be assigned only when it is created, so we can use readonly to define the read-only attribute:

interface Person {
    readonly id: number;
    name: string;
    age?: number;
    [propName: string]: any;
}

let tom: Person = {
    id: 89757,
    name: 'Tom',
    gender: 'male'
};

tom.id = 9527;

// index.ts(14,5): error TS2540: Cannot assign to 'id' because it is a constant or a read-only property.

In the above example, after initialization with the attribute id defined by readonly, it is assigned again, so an error is reported.

Note that the read-only constraint exists when the object is assigned for the first time, not when the read-only attribute is assigned for the first time:

interface Person {
    readonly id: number;
    name: string;
    age?: number;
    [propName: string]: any;
}

let tom: Person = {
    name: 'Tom',
    gender: 'male'
};

tom.id = 89757;

// index.ts(8,5): error TS2322: Type '{ name: string; gender: string; }' is not assignable to type 'Person'.
//   Property 'id' is missing in type '{ name: string; gender: string; }'.
// index.ts(13,5): error TS2540: Cannot assign to 'id' because it is a constant or a read-only property.

In the above example, there are two error messages. The first is that the id is not assigned when tom is assigned.

The second point is that when tom.id is assigned a value, an error is reported because it is a read-only attribute.

reference resources

Posted by contra10 on Sun, 24 Oct 2021 00:27:58 -0700