Article directory
1. Variable declaration
1.1 var
- Scope
- Repeat statement
1.2 let
- block scope
- cannot be declared repeatedly in the same block
1.3 const
- The declaration must also be assigned a value
- It must be stated that it cannot be changed
- Objects can be modified
- block scope
1.4 let
vs const
Usingthe principle of least privilege, all variables except those you plan to modify should be usedconst
. The basic principle is that if a variable does not need to be written to, then other people using the code cannot write to it, and think about why these variables need to be reassigned. Using const
also makes it easier for us to speculate on the flow of data.
2. Basic data types
2.1 Boolean values
let isDone: boolean = false;
2.2 Numbers
let amount: number = 6;
2.3 String
-
type
-
template string
- Support newline
- Supports inline expressions
-
Like JavaScript, you can use double quotes or single quotes. Single quotes are recommended.
let nickname: string = '张三';
You can also use template strings (newlines + embedded expressions):
let nickname: string = `Gene`;
let age: number = 37;
let sentence: string = `Hello, my nickname is ${
nickname }.
I'll be ${
age + 1 } years old next month.`;
2.4 Array
TypeScript can operate on array elements just like JavaScript. There are two ways to define an array. The first one can be followed by []
after the element type to indicate an array composed of elements of this type:
let list: number[] = [1, 2, 3];
The second way is to use array generics,Array<元素类型>
:
let list: Array<number> = [1, 2, 3];
2.5 tuples
The tuple type allows the representation of an array with a known number and type of elements, and the types of each element do not have to be the same. For example, you can define a pair of tuples whose values are of type string
and number
respectively.
// Declare a tuple type
let x: [string, number];
// Initialize it
x = ['hello', 10]; // OK
// Initialize it incorrectly
x = [10, 'hello']; // Error
2.6 Object
- Allows assigning any value
- But you can't call any method, even if it does
let foo: Object = {
name: 'Jack',
age: 18
}
Just know it, rarely used, no type checking and syntax prompts
2.7 Any
Sometimes, we want to specify a type for variables whose type is not clear at the programming stage. These values may come from dynamic content, such as from user input or third-party code libraries. In this case, we don't want the type checker to check these values and just let them pass the compile-time check. Then we can use the any
type to mark these variables:
let notSure: any = 4;
notSure = "maybe a string instead";
notSure = false; // okay, definitely a boolean
2.8 Void
void
The type is like the opposite of the any
type, which means there is no type. When a function does not return a value, you will usually see that its return value type is void
:
function warnUser(): void {
alert("This is my warning message");
}
Declaring a variable of type void
is of little use because you can only assign it undefined
and null
:
let unusable: void = undefined;
2.9 Null and Undefined
is similar to void
, but their types are not very useful:
// Not much else we can assign to these variables!
let u: undefined = undefined;
let n: null = null;
By defaultnull
and undefined
are subtypes of all types. That is to say, you can assign null
and undefined
to variables of type number
.
However, when you specify the --strictNullChecks
tag, null
and undefined
can only be assigned to < a i=4> and each of them. This avoids manycommon problems. Maybe somewhere you want to pass in a or or , you can use the union type . void
string
null
undefined
string | null | undefined
Note: We recommend using
--strictNullChecks
as much as possible, because it makes your code more rigorous and can greatly reduce the chance of errors.
2.10 Type inference
Sometimes you will encounter a situation where you know the details of a value better than TypeScript. Usually this happens when you clearly know that an entity has a more exact type than its existing type.
ByType assertionThis way you can tell the compiler, "Trust me, I know what I'm doing." Type assertions are like type conversions in other languages, but no special data checking or destructuring is performed. It has no runtime impact and only works during the compilation phase. TypeScript will assume that you, the programmer, have made the necessary checks.
Type assertions come in two forms. One is the "angle bracket" syntax:
let someValue: any = "this is a string";
let strLength: number = (<string>someValue).length;
The other isas
Syntax:
let someValue: any = "this is a string";
let strLength: number = (someValue as string).length;
The two forms are equivalent. Which one to use is mostly a matter of personal preference; however, when you use JSX in TypeScript, only the as
syntax assertion is allowed.
2.11 Others
ReadonlyArray<T>
All mutable methods of the array are removed to ensure that the array cannot be modified after it is created.
3. Interface
One of the core principles of TypeScript is type checking the structure of a value. It is sometimes called "duck typing" or "structural subtyping". In TypeScript, the role of interfaces is to name these types and define contracts for your code or third-party code.
3.1 Basic example
function printLabel(labelledObj: {
label: string }) {
console.log(labelledObj.label);
}
let myObj = {
size: 10, label: "Size 10 Object" };
printLabel(myObj);
The type checker will look at the call to printLabel
. printLabel
has a parameter, and requires that this object parameter have an attribute named label
of type string
. It should be noted that the object parameter we pass in will actually contain many properties, but the compiler will only check whether those required properties exist and whether their types match. However, sometimes TypeScript is not so loose, as we will explain a little below.
Let's rewrite the above example, this time using an interface to describe: it must contain a label
attribute and type string
:
interface LabelledValue {
label: string;
}
function printLabel(labelledObj: LabelledValue) {
console.log(labelledObj.label);
}
let myObj = {
size: 10, label: "Size 10 Object"};
printLabel(myObj);
3.2 Optional attributes
Not all properties in the interface are required. Some exist only under certain conditions, or may not exist at all. Optional attributes are commonly used when applying the "option bags" pattern, where only some of the attributes in the parameter object passed to the function are assigned values.
interface SquareConfig {
color?: string;
width?: number;
}
function createSquare(config: SquareConfig): {
color: string; area: number} {
let newSquare = {
color: "white", area: 100};
if (config.color) {
newSquare.color = config.color;
}
if (config.width) {
newSquare.area = config.width * config.width;
}
return newSquare;
}
let mySquare = createSquare({
color: "black"});
3.3 Read-only attributes
Some object properties can only modify their values when the object is first created. You can specify read-only properties by using readonly
before the property name:
interface Point {
readonly x: number;
readonly y: number;
}
You can construct an Point
by assigning an object literal. After assignment, x
and y
can no longer be changed.
let p1: Point = {
x: 10, y: 20 };
p1.x = 5; // error!
readonly
vs const
- Constants use const
- Object properties use readonly
4. Destructuring assignment
4.1 Array destructuring
let input = [1, 2];
let [first, second] = input;
console.log(first); // outputs 1
console.log(second); // outputs 2
The above writing is equivalent to:
first = input[0];
second = input[1];
Use destructuring assignment to exchange variables:
[first, second] = [second, first];
Function parameter destructuring:
function f ([first, second]: [number, number]) [
console.log(first)
console.log(second)
]
f(1, 2)
Deconstruct the remaining parameters:
let [first, ...rest] = [1, 2, 3, 4]
console.log(first) // 1
console.log(rest) // [2, 3, 4]
Other parameters can also be ignored:
let [first] = [1, 2, 3, 4];
console.log(first); // outputs 1
Or skip destructuring:
let [, second, , fourth] = [1, 2, 3, 4]
4.2 Object destructuring
4.2.1 Basic usage
Example one:
let o = {
a: "foo",
b: 12,
c: "bar"
};
let {
a, b } = o;
Just like array destructuring, you can use assignment without declaration:
let a: number,
b: number;
({
a, b} = {
a: 123, b: 456})
console.log(a, b) // 123 456
You can create remaining variables within the object using the ...
syntax:
let {
a, ...passthrough } = o;
let total = passthrough.b + passthrough.c.length;
4.2.2 Attribute destructuring and renaming
You can also give properties different names:
let {
a: newName1, b: newName2 } = o;
Note that the colon here does not indicate the type. If you want to specify its type, you still need to write the complete pattern after it.
let {
a, b}: {
a: string, b: number} = o;
4.2.3 Default value
function keepWholeObject(wholeObject: {
a: string, b?: number }) {
let {
a, b = 1001 } = wholeObject;
}
4.3 Expand operator
- expand array
- expand object
- Will not expand method
4.4 Destructuring assignment for function declaration
type C = {
a: string, b?: number}
function f ({
a, b}: C): void {
// ...
}