1. Meet the Typescript
The introduction of TypeScript
TypeScript is an open source, cross-platform programming language developed by Microsoft. It is a superset of JavaScript that will eventually be compiled into JavaScript code.
Microsoft released the first public version of TypeScript in October 2012 and released TypeScript on June 19, 2013 after a preview release
TypeScript was written by anders hejlsberg, the chief architect of C#. It is an open source and cross-platform programming language.
TypeScript extends JavaScript’s syntax so that any existing JavaScript program can run in a TypeScript environment.
TypeScript is designed for large application development and can be compiled into JavaScript.
TypeScript is a superset of JavaScript that provides a type system and support for ES6+. It was developed by Microsoft and its code is opened on GitHub (new Window)
The characteristics of the TypeScript
TypeScript has three main features:
- It starts with JavaScript and ends with JavaScript
TypeScript compiles clean, concise JavaScript code and runs in any browser, Node.js environment, and any JavaScript engine that supports ECMAScript 3 (or later).
- Powerful type system
The type system allows JavaScript developers to use efficient development tools and common operations such as static checking and code refactoring when developing JavaScript applications.
- Advanced JavaScript
TypeScript offers the latest and evolving JavaScript features, including those from ECMAScript 2015 and future proposals, such as asynchronous functionality and Decorators, to help build robust components.
conclusion
TypeScript is becoming increasingly popular in the community, and it works well on large projects as well as base libraries, greatly improving our development efficiency and experience.
2. Install the TypeScript
Run the following command from the command line to install TypeScript globally
npm install -g typescript
Copy the code
After the installation is complete, run the following command on the console to check whether the installation is successful (3.x) :
tsc -V
Copy the code
The first TypeScript program
Write TS programs
src/helloworld.ts
function greeter (person) {
return 'Hello, ' + person
}
let user = 'Yee'
console.log(greeter(user))
Copy the code
Compiling code by hand
We use the.ts extension, but this code is just JavaScript.
On the command line, run the TypeScript compiler:
tsc helloworld.ts
Copy the code
The output is a helloworld.js file that contains the same JavsScript code as the input file.
On the command line, run this code from Node.js:
node helloworld.js
Copy the code
Console output:
Hello, Yee
Copy the code
Vscode automatically compiles
Json TSC --init 2). Json config "outDir": "./js", "strict": false, 3). Start a monitoring task: Terminal -> Run Task -> Monitor tsconfig.jsonCopy the code
Type annotations
Let’s take a look at the advanced features that TypeScript tools bring. Add a string annotation to the argument to the person function as follows:
function greeter (person: string) {
return 'Hello, ' + person
}
let user = 'Yee'
console.log(greeter(user))
Copy the code
Type annotations in TypeScript are a lightweight way to add constraints to functions or variables. In this example, we want the greeter function to take a string argument. Then try passing a call to greeter into an array:
function greeter (person: string) {
return 'Hello, ' + person
}
let user = [0.1.2]
console.log(greeter(user))
Copy the code
Recompile and you should see an error:
error TS2345: Argument of type 'number[]' is not assignable to parameter of type 'string'.
Copy the code
Similarly, try to remove all arguments to the greeter call. TypeScript tells you that the function was called with an unexpected number of arguments. In both cases, TypeScript provides static code analysis that examines the code structure and provides type annotations.
Note that the greeter.js file was created despite the error. Even if your code has errors, you can still use TypeScript. But in this case, TypeScript warns you that the code may not perform as expected.
interface
Let’s continue to extend the sample application. Here we use an interface to describe an object with firstName and lastName fields. In TypeScript, two types are compatible only if the structure inside them is compatible. This allows us to implement the interface without explicitly using the IMPLEMENTS statement, as long as we ensure that the required structure is included.
interface Person {
firstName: string
lastName: string
}
function greeter (person: Person) {
return 'Hello, ' + person.firstName + ' ' + person.lastName
}
let user = {
firstName: 'Yee'.lastName: 'Huang'
}
console.log(greeter(user))
Copy the code
class
Finally, let’s rewrite this example using classes. TypeScript supports new features of JavaScript, such as class-based object-oriented programming.
Let’s create a User class with a constructor and some public fields. Because the fields of the class contain the fields required by the interface, they are compatible.
Also note that I will specify all the member variables in the class declaration so that it is easy to see.
class User {
fullName: string
firstName: string
lastName: string
constructor (firstName: string, lastName: string) {
this.firstName = firstName
this.lastName = lastName
this.fullName = firstName + ' ' + lastName
}
}
interface Person {
firstName: string
lastName: string
}
function greeter (person: Person) {
return 'Hello, ' + person.firstName + ' ' + person.lastName
}
let user = new User('Yee'.'Huang')
console.log(greeter(user))
Copy the code
Re-run TSC Greeter. ts and you’ll see that the TypeScript class is just a syntactic sugar that is essentially an implementation of JavaScript functions.
conclusion
Now that you have a general idea of TypeScript, let’s take a look at some common TypeScript syntax in the next chapter.
4.Typescript common syntax
The data type
TypeScript supports almost the same data types as JavaScript, and it also provides useful enumerated types for us to use
Personal habit: By default, it is generally not added if the corresponding identifier type can be derived
number
Like JavaScript, all numbers in TypeScript are floating point numbers. These floating point numbers are of type number. In addition to supporting decimal and hexadecimal literals, TypeScript also supports binary and octal literals introduced in ECMAScript 2015.
let a1: number = 10 / / decimal
let a2: number = 0b1010 / / binary
let a3: number = 0o12 / / octal
let a4: number = 0xa // Hexadecimal
Copy the code
string
String is a string and can be expressed in single or double quotation marks:
let name = "yunmu"
let age = 18
// ES6 template strings are also supported to concatenate variables and strings:
let message3 = `name:${name} age:${age}`
console.log(message3)
Copy the code
boolean
The most basic data types are simple true/false values, called Boolean in JavaScript and TypeScript (and in other languages as well).
let isDone: boolean = false;
isDone = 20 > 30;
Copy the code
Undefined and null
In TypeScript, undefined and null have their own types called undefined and NULL, respectively. Their type by itself is not very useful
let u: undefined = undefined
let n: null = null
// By default null and undefined are subtypes of all types. This means that you can assign null and undefined to variables of type number.
Copy the code
Symbol
In ES5, if we are not allowed to add the same attribute name to the object
But we can also define the same name through symbol, because the symbol function returns a unique value
const title1 = Symbol("title")
const title2 = Symbol('title')
const info = {
[title1]: "Programmer",
[title2]: "Teacher"
}
Copy the code
Array
TypeScript, like JavaScript, can manipulate array elements and can be defined in two ways
First, the element type can be followed by [] to represent an array of elements of that type:
let list1: number[] = [1.2.3]
Copy the code
The second way is to use Array generics, Array< element type >
let list2: Array<number> = [1.2.3] React JSX conflicts with react JSX
Copy the code
If any other type is added to the array, an error is reported
Object
Object means a non-primitive type, that is, a type other than number, string, or Boolean
const obj: object = {
name: "yunmu".age: 18
}
// Ordinary objects do not have the name attribute, which is best derived from typescript itself
console.log(obj.name)
Copy the code
function fn2(obj:object) :object {
console.log('fn2()', obj)
return {}
// return undefined
// return null
}
console.log(fn2(new String('abc')))
// console.log(fn2('abc') // error
console.log(fn2(String))
Copy the code
any
In some cases, we can’t really determine the type of a variable, and maybe it will change a bit, so we can use any
We can do anything on a variable of type any, including fetching nonexistent properties and methods
We assign any values to a variable of type any, such as numbers or strings
We can use any in cases where we don’t want to add a specified type annotation, or where a type annotation is missing when we introduce some third-party libraries
let message: any = "Hello World"
message = 123
message = true
message = {
}
message() / / an error
message.toUpperCase()
const arr: any[] = []
Copy the code
unknown
Unknown is a special type in TypeScript that describes variables of uncertain type
function foo() {
return "abc";
}
function bar() {
return 123;
}
// The unknown type can only be assigned to any and unknown types
The any type can be assigned to any type
let flag = true;
let result: unknown; // It is best not to use any
if (flag) {
result = foo();
} else {
result = bar();
}
// An error is reported if any is not used
let message: string = result;
let num: number = result;
console.log(result);
Copy the code
void
Void is usually used to specify that a function has no return value, so its return value is void
- We can assign null and undefined to void, which means functions can return either null or undefined
// The function returns void by default
function sum(num1: number, num2: number) :void {
console.log(num1 + num2);
}
Copy the code
never
Never indicates the type of value that never occurs, such as a function
If a function is in an infinite loop or throws an exception, does the function return something?
function foo() :never {
/ / death cycle
while(true) {}}// Throw an error
function bar() :never {
throw new Error()}function handleMessage(message: string | number | boolean) {
switch (typeof message) {
case "string":
console.log("String processing for message");
break;
case "number":
console.log("Number processing to handle message");
break;
case "boolean":
console.log("Boolean processing method handles message");
break;
default:
const check: never= message; }}// The function that passes any other type will assign never to an error
handleMessage("abc");
handleMessage(123);
handleMessage(true);
Copy the code
tuple
The tuple type allows you to represent an array with a known number and type of elements that need not be of the same type. For example, you can define a pair of tuples of type string and number.
const info: [string.number] = ["hello".10];
info = ["yunmu".18];
// When accessing an element with a known index, the correct type is obtained:
const name = info[0];
Copy the code
Application:
function useState<T> (state: T) :T, (newState: T) = >void] {
let currentState = state;
const changeState = (newState: T) = > {
currentState = newState;
};
// const info: [string, number] = ["abc", 18];
const tuple: [T, (newState: T) = > void] = [currentState, changeState];
return tuple;
}
const [counter, setCounter] = useState(10);
setCounter(1000);
const [title, setTitle] = useState("abc");
const [flag, setFlag] = useState(true);
Copy the code
Enumerated type
Enumeration types are used to give friendly names to a set of values
Enumerations allow developers to define a set of named constants, which can be numbers or strings
enum Color {
Red,
Green,
Blue
}
// Enumeration values start at 0 by default
// Get the corresponding enumeration value based on the specific name
let myColor: Color = Color.Green / / 0
console.log(myColor, Color.Red, Color.Blue)
Copy the code
By default, elements are numbered from 0. You can also manually specify the values of the members
Let’s change the above example to number from 1:
enum Color {Red = 1, Green, Blue}
let c: Color = Color.Green
Copy the code
Alternatively, all manual assignments are used:
enum Color {Red = 1, Green = 2, Blue = 4}
let c: Color = Color.Green
Copy the code
One of the conveniences provided by an enumerated type is that you can refer to its name by enumeration
For example, if we know that the value is 2, but are not sure which name it maps to in Color, we can look up the corresponding name
enum Color {Red = 1, Green, Blue}
let colorName: string = Color[2]
console.log(colorName) // 'Green'
Copy the code
enum Direction {
LEFT = "LEFT",
RIGHT = "RIGHT",
TOP = "TOP",
BOTTOM = "BOTTOM",}function turnDirection(direction: Direction) {
switch (direction) {
case Direction.LEFT:
console.log("Change the character's direction to the left.");
break;
case Direction.RIGHT:
console.log("Change the direction of the character to the right.");
break;
case Direction.TOP:
console.log("Change the direction of the character up.");
break;
case Direction.BOTTOM:
console.log("Change the direction of the character downward.");
break;
default:
const foo: never = direction;
break;
}
}
turnDirection(Direction.LEFT);
turnDirection(Direction.RIGHT);
turnDirection(Direction.TOP);
turnDirection(Direction.BOTTOM);
Copy the code
Function parameter and return value types
TypeScript allows us to specify the types of function arguments and return values
Annotate function arguments with type: num1: number, num2: number
function sum(num1: number, num2: number) {
return num1 + num2;
}
sum(123); / / an error
Copy the code
Comment the return value with a type comment: (): number. In development, it is usually possible to omit the type of the return value (automatic derivation).
function sum(num1: number, num2: number) :number {
return num1 + num2;
}
Copy the code
Anonymous functions are a little different from function declarations. When a function appears in a place where TypeScript can determine how the function will be called, the function’s parameters are automatically typed, right
const names = ["abc"."cba"."nba"];
// item is a string derived from the context in which the function is executed. Type annotations can be omitted because the context in which the function is executed helps determine the type of the argument and return value
names.forEach(function (item) {
console.log(item.split(""));
});
Copy the code
Object type
Sometimes we want a function to take an object as an argument
We use object types
Can we add an attribute to an object and tell TypeScript what type the attribute needs to be, or any if not specified
Attributes can be used between, or; The last delimiter is optional
function printPoint(point: { x: number; y: number }) {
console.log(point.x);
console.log(point.y);
}
printPoint({ x: 123.y: 321 });
Copy the code
The object type can also specify which attributes are optional. Can you add one after the attribute?
function printPoint(point: { x: number; y: number; z? :number }) {
console.log(point.x);
console.log(point.y);
console.log(point.z);
}
printPoint({ x: 123.y: 321 });
printPoint({ x: 123.y: 321.z: 111 });
Copy the code
The joint type
TypeScript’s type system allows us to build new types from existing types using multiple operators
The first way to combine types is Union types
- A union type is a type composed of two or more other types that can represent a value of any one of them
- Each of the union types is called union’s members.
/ / number | string | Boolean joint type
function printID(id: number | string | boolean) {
console.log(id);
}
Copy the code
Be careful when using union types, because we may get different types of values
For example, if we get a number, we can’t call a string method
We can use narrow associations to infer more specific types
function printID(id: number | string | boolean) {
Use special care when using values of union types
/ / narrow, narrow
if (typeof id === "string") {
// TypeScript helps determine that the ID must be a string
console.log(id.toUpperCase());
} else {
console.log(id);
}
}
printID(123);
printID("abc");
printID(true);
Copy the code
The relationship between optional types and union types
/ / a parameter to an optional type, it is similar and the parameter is the type | undefined type of joint
function foo(message? :string) {
console.log(message)
}
Copy the code
Type the alias
We used to write objects and union types through type annotations, and it was a bit cumbersome to use the same type multiple times
We can define a type alias using type.
type IDType = string | number | boolean;
type PointType = {
x: number;
y: number; z? :number;
};
function printId(id: IDType) {}
function printPoint(point: PointType) {}
Copy the code
Type assertion AS
Sometimes TypeScript cannot get specific Type information; we need to use Type Assertions.
For example, with Document.getelementById, TypeScript only knows that this function returns HTMLElement, but it doesn’t know its type
const el = document.getElementById("yun") as HTMLImageElement;
el.src = "Url";
Copy the code
// Person is the parent of Student
class Person {}
class Student extends Person {
studying(){}}function sayHello(p: Person) {
(p as Student).studying();
}
const stu = new Student();
sayHello(stu);
Copy the code
Type inference
Type inference: TS will infer a type when no explicit type is specified
There are two cases: 1. When defining a variable, it is assigned to the corresponding type. 2. The variable is defined without an assignment and is inferred to be of type any
/* The variable is assigned to the corresponding type */
let b9 = 123 // number
// b9 = 'abc' // error
/* The variable is defined without an assignment and is inferred to be of type any */
let b10 / / any type
b10 = 123
b10 = 'abc'
Copy the code
Non-null type assertion!
We can use non-null type assertions when we are sure that the parameter passed in has a value
Non-empty assertions use! , indicating that an identifier can be determined to have a value, skipping ts’s detection of it at compile time
function printMessageLength(message? :string) {
// if (message) {
// console.log(message.length)
// }
console.log(message! .length); }Copy the code
Optional chain
It is an added feature in ES11 (ES2020)
Optional chain using optional chain operator? .
If the property of the object does not exist, it will short-circuit and return undefined. If it exists, execution will continue
type Person = {
name: string; friend? : {name: string; age? :number; girlFriend? : {name: string;
};
};
};
const info: Person = {
name: "yun".friend: {
name: "kobe".girlFriend: {
name: "lily",}}};console.log(info.friend?.name);
console.log(info.friend?.age);
console.log(info.friend?.girlFriend?.name);
Copy the code
?? And!!!!! The operator
!!!!! The operator
To cast an additional type to a Boolean type, in a manner similar to Boolean(variables)
?? The operator
It is a new feature in ES11 that returns the right-hand operand if the left-hand side of an operator is null or undefined, otherwise returns the left-hand operand
constflag = !! message;console.log(flag);
let message: string | null = "Hello World";
const content = message ?? "Hello, Yunmu.";
console.log(content);
Copy the code
Literal type
// "Hello World" can also be a type, called a literal type
const message: "Hello World" = "Hello World";
// The meaning of literal types is that union types must be combined
type Alignment = "left" | "right" | "center";
let align: Alignment = "left";
align = "right";
align = "center";
Copy the code
Literal reasoning
Let’s look at the following code
type Method = "GET" | "POST";
function request(url: string, method: Method) {}
const options = {
url: "https://www.coderwhy.org/abc".method: "POST",}as const;
request(options.url, options.method);
Copy the code
Method: {url: string, method: string}}, so we can’t assign a string to a literal type
A:
type Request = {
url: string;
method: Method;
};
constOptions: Request = {url: "https://www.coderwhy.org/abc".method: "POST"};Copy the code
Method 2:
request(options.url, options.method as Method);
Copy the code
Three:
const options = {
url: "https://www.coderwhy.org/abc".method: "POST",}as const
Copy the code
Type to reduce the
Type Narrowing.
We can change TypeScript execution paths with typeof padding === “number” statements
Will be able to shrink a smaller type in a given path than when declared, the process is called narrowing
And typeof padding === “number is called type Guards.
Common type protection
- typeof
- Equality diminishes (e.g. ===,! = =)
- instanceof
- in
typeof
You can operate on different values using typeof check types
type IDType = number | string;
function printID(id: IDType) {
if (typeof id === "string") {
console.log(id.toUpperCase());
} else {
console.log(id); }}Copy the code
Equal to narrow
We can use Switch or some equality operator to express equality (such as ===, ==,! = =,! =)
type Direction = "left" | "right" | "top" | "bottom";
function printDirection(direction: Direction) {
/ / 1. If judgment
if (direction === 'left') {
console.log(direction)
} else if(a)/ / 2. The switch of judgment
switch (direction) {
case 'left':
console.log(direction)
break;
case. }}Copy the code
instanceof
Operator to check whether a value is an instance of another value
function printTime(time: string | Date) {
if (time instanceof Date) {
console.log(time.toUTCString());
} else {
console.log(time); }}Copy the code
class Student {
studying(){}}class Teacher {
teaching(){}}function work(p: Student | Teacher) {
if (p instanceof Student) {
p.studying();
} else{ p.teaching(); }}const stu = new Student();
work(stu);
Copy the code
in
The IN operator is used to determine that the specified property is in the specified object or its stereotype chain, and returns true
type Fish = {
swimming: () = > void;
};
type Dog = {
running: () = > void;
};
function move(animal: Fish | Dog) {
if ("swimming" in animal) {
animal.swimming();
} else{ animal.running(); }}const fish: Fish = {
swimming() {
console.log("swimming"); }}; move(fish);Copy the code
TypeScript function types
Functions are very common in Javascript, even first-class citizens (passed as arguments or return values)
In TypeScript we can write Function Type Expressions to represent Function types
1. When a function is used as a parameter, write a type in the parameter
function foo() {}
type FooFnType = () = > void;
function bar(fn: FooFnType) {
fn();
}
bar(foo);
Copy the code
2. Write the type of the function when defining constants
// (num1: number, num2: number) => number
// A function that takes two arguments: num1 and num2, both of type number
// Return number again
type AddFnType = (num1: number, num2: number) = > number;
const add: AddFnType = (a1: number, a2: number) = > {
return a1 + a2;
};
Copy the code
Optional type of argument
// Optional types must be written after required types
function foo(x: number, y? :number) {}
foo(20.30);
foo(20);
Copy the code
The default parameters
General Order Mandatory parameters – Parameters with default values – Optional parameters
function foo(y: number, x: number = 20) {
console.log(x, y);
}
foo(30);
Copy the code
The remaining parameters
The residual argument syntax allows us to put an indefinite number of arguments into an array
function sum(initalNum: number. nums:number[]) {
let total = initalNum;
for (const num of nums) {
total += num;
}
return total;
}
console.log(sum(20.30));
console.log(sum(20.30.40));
console.log(sum(20.30.40.50));
Copy the code
This type of
This is a Javascript keyword that binds different values in different contexts
By default, this can be derived
const info = {
name: "yunmu".eating() {
console.log(this.name + " eating")
}
}
info.eating()
Copy the code
We can also specify this
type ThisType = { name: string };
function eating(this: ThisType, message: string) {
console.log(this.name + " eating", message);
}
const info = {
name: "why".eating: eating,
};
// Implicit binding
info.eating("Ha ha ha.");
// Show the binding
eating.call({ name: "kobe" }, "Hehe hehe");
eating.apply({ name: "james"},"Hey hey hey."]);
Copy the code
Function overloading
What if we wrote an add function that wanted to add string and number types?
function add(a1: number | string, a2: number | string) {
return a1 + a2; / / an error
}
Copy the code
Solution 1: Union type
function add(a1: number | string, a2: number | string) {
if (typeof a1 === "number" && typeof a2 === "number") {
return a1 + a2;
} else if (typeof a1 === "string" && typeof a2 === "string") {
return a1 + a2;
}
}
add(10.20);
/** * There are two disadvantages to combining types: * 1. A lot of logical judgment (type narrowing) * 2. The type of the return value is still undetermined */
Copy the code
Solution 2: function overload
Multiple functions with the same name but different parameters are overloaded functions
We can write different overload signatures to indicate that functions can be called in different ways
It is common to write two or more overloaded signatures and then write a generic function implementation
function add(num1: number, num2: number) :number; // No function body
function add(num1: string, num2: string) :string;
function add(num1: any, num2: any) :any {
if (typeof num1 === "string" && typeof num2 === "string") {
return num1.length + num2.length;
}
return num1 + num2;
}
const result1 = add(20.30);
const result2 = add("abc"."cba");
console.log(result1);
console.log(result2);
Copy the code
In function overloading, the implementation function cannot be called directly
Combine types and overloads
We now have a requirement to define a function that can pass in strings or arrays and get their lengths
As above, there are two implementations
Scheme 1: Combination type
function getLength(args: string | any[]) {
return args.length
}
console.log(getLength("abc"))
console.log(getLength([123.321.123]))
Copy the code
Scheme 2: function overloading
function getLength(args: string) :number;
function getLength(args: any[]) :number;
function getLength(args: any) :number {
return args.length;
}
console.log(getLength("abc"));
console.log(getLength([123.321.123]));
Copy the code
In development, select federated types whenever possible
Class in the Typescript
Before ES6 we needed to implement classes and inheritance through a chain of functions and stereotypes
Starting with ES6, the class keyword was introduced to make it easier to define classes and inheritance
In practice, though, we use more functional programming ideas
But classes are also very encapsulation, and we need to master it
The definition of a class
We usually use the class keyword to define a class
In the object-oriented world, anything can be described using the structure of a class
Classes contain unique properties and methods
Let’s define a Person class using class
We can declare the attributes of a class and their corresponding types inside the class. No declaration, default is any
In the default strictPropertyInitialization mode, we must can give attribute set initialization values
If the implementation doesn’t want to use name! : Syntax for string
The class has its own constructor, called when we create an instance with the new keyword
Classes can have their own functions, defined functions called methods
class Person { name! :string;
age: number;
constructor(name: string, age: number) {
// this.name = name;
this.age = age;
}
eating() {
console.log(this.name + " eating"); }}const p = new Person("yun".18);
console.log(p.name);
console.log(p.age);
p.eating();
Copy the code
Class inheritance
One of the features of object orientation is inheritance, which can not only reduce the amount of code we use, but also the premise of using polymorphism
We use the extends keyword for inheritance and super in subclasses to access the parent class
Let’s look at the Student class inheriting from Person
The Student class can have its own properties and methods, and will inherit the properties and methods of Person
In the constructor, we can call the constructor of the parent class with super to initialize the properties in the parent class
class Person {
name: string
age: number
constructor(name: string, age: number) {
this.name = name
this.age = age
}
eating() {
console.log("Eating 100 line")}}class Student extends Person {
sex: number
constructor(name: string, age: number, sex: number) {
// super calls the constructor of the parent class
super(name, age)
this.sex = sex
}
eating() {
console.log("student eating")
super.eating()
}
studying() {
console.log("studying")}}const stu = new Student("yun".18.111)
console.log(stu.name)
console.log(stu.age)
console.log(stu.sex)
stu.eating()
Copy the code
Class of polymorphism
Polymorphic premise: A reference to a parent class refers to a subclass object
It looks like the same type, but the method is not the same
class Animal {
action() {
console.log("animal action"); }}class Dog extends Animal {
action() {
console.log("dog running!!!"); }}class Fish extends Animal {
action() {
console.log("fish swimming"); }}// animal: dog/fish
// The purpose of polymorphism is to write more universal code
function makeActions(animals: Animal[]) {
animals.forEach((animal) = > {
animal.action();
});
}
makeActions([new Dog(), new Fish(), new Person()]);
Copy the code
Class member modifier
In TypeScript, class properties and methods support three modifiers: public, private, and protected
- Public modifies properties or methods that are public and visible anywhere, and properties written by default are public
- Private modifies properties or methods that are visible only in the same class and are private
- Protected modifies the properties or methods that are visible and protected only in the class itself and its subclasses
private
class Person {
private name: string = "";
// Encapsulates two methods that access name
getName() {
return this.name;
}
setName(newName) {
this.name = newName; }}const p = new Person();
console.log(p.getName());
p.setName("yun");
Copy the code
protected
// protected: Accessible within the class and in subclasses
class Person {
protected name: string = "123";
}
class Student extends Person {
getName() {
return this.name; }}const stu = new Student();
console.log(stu.getName());
Copy the code
Read-only property readonly
If you have an attribute that you don’t want the outside world to modify arbitrarily, but only want to use after fixing the value, you can use readonly
class Person {
// 1. Read-only attributes can be assigned in the constructor and cannot be modified after assignment
// 2. The attribute itself cannot be modified, but if it is an object type, the attribute in the object can be modified
readonly name: string; age? :number;
readonlyfriend? : Person;constructor(name: string, friend? : Person) {
this.name = name;
this.friend = friend; }}const p = new Person("yun".new Person("kobe"));
console.log(p.name);
console.log(p.friend);
// You cannot change friend directly
// p.friend = new Person("james")
if (p.friend) {
p.friend.age = 30;
}
Copy the code
getters/setters
Before, we had some private properties that we couldn’t access directly, and some properties that we wanted to listen to for getters and setters, so we could use accessors
class Person {
private _name: string;
constructor(name: string) {
this._name = name;
}
// Accessor setter/getter
// setter
set name(newName) {
this._name = newName;
}
// getter
get name() {
return this._name; }}const p = new Person("yun");
p.name = "yunmu";
console.log(p.name);
Copy the code
Static members
The members and methods we defined in the class above are at the object level
In development, we also sometimes need to define members and methods at the class level
Defined in TypeScript with the static keyword
class Student {
static time: string = "PM";
static attendClass() {
console.log("To learn."); }}console.log(Student.time);
Student.attendClass();
Copy the code
An abstract class abstract
Inheritance is a prerequisite for the use of polymorphism
So when defining a lot of generic calling interfaces, we usually let the caller pass in the parent class to make the call more flexible through polymorphism
However, the parent class itself may not need to implement specific methods, so methods defined in the parent class can be defined as abstract methods
What are abstract methods? Methods that are not implemented in TypeScript (without a method body) are abstract methods
- Abstract methods must exist in abstract classes
- Abstract classes are classes that use abstract declarations
Abstract classes have the following characteristics
- Abstract classes cannot be instantiated (that is, cannot be created by new)
- Abstract methods must be implemented by subclasses
function makeArea(shape: Shape) {
return shape.getArea();
}
abstract class Shape {
abstract getArea(): number;
}
class Rectangle extends Shape {
private width: number;
private height: number;
constructor(width: number, height: number) {
super(a);this.width = width;
this.height = height;
}
getArea() {
return this.width * this.height; }}class Circle extends Shape {
private r: number;
constructor(r: number) {
super(a);this.r = r;
}
getArea() {
return this.r * this.r * 3.14; }}const rectangle = new Rectangle(20.30);
const circle = new Circle(10);
console.log(makeArea(rectangle));
console.log(makeArea(circle));
// All the following errors are reported
// makeArea(new Shape())
// makeArea(123)
// makeArea("123")
Copy the code
The type of the class
Classes themselves can also be a data type
class Person {
name: string = "123";
eating(){}}const p = new Person(); / / the Person type
const p1: Person = {
name: "yun".eating(){}};function printPerson(p: Person) {
console.log(p.name);
}
printPerson(new Person());
printPerson({ name: "kobe".eating: function () {}});Copy the code
interface
Declaration of interfaces
We can declare object types through type aliases
type InfoType = {name: string.age: number}
Copy the code
You can also use an interface
interface IInfoType {
name: string;
age: number;
}
const info: IInfoType = {
name: "yun".age: 18};Copy the code
Optional attribute
We can also define optional attributes in the interface
interface IInfoType {
name: string; age? :number; friend? : {name: string;
};
}
const info: IInfoType = {
name: "yun".age: 18.friend: {
name: "kobe",}};console.log(info.friend?.name);
Copy the code
Read-only property
Read-only attributes can also be defined in an interface
This means that the value cannot be changed after initialization
interface IInfoType {
readonly name: string;
age: number;
readonly friend: {
name: string;
};
}
const info: IInfoType = {
name: "why".age: 18.friend: {
name: "kobe",}}; info.name ="123" / / an error
info.friend = {} / / an error
info.friend.name = "yunmu" // OK
Copy the code
The index type
The interface was used to define the object type, where the property name, type, and method are defined
// Use interface to define index type index
interface IndexLanguage {
[index: number] :string
}
const frontLanguage: IndexLanguage = {
0: "HTML".1: "CSS".2: "JavaScript".3: "Vue"
}
interface ILanguageYear {
[name: string] :number
}
const languageYear: ILanguageYear = {
"C": 1972."Java": 1995."JavaScript": 1996."TypeScript": 2014
}
Copy the code
Function types
Interfaces are used to define common attributes and methods in objects, but they can also be used to define function types
// Callable interface
interface CalcFn {
(n1: number.n2: number) :number;
}
function calc(num1: number, num2: number, calcFn: CalcFn) {
return calcFn(num1, num2);
}
const add: CalcFn = (num1, num2) = > {
return num1 + num2;
};
calc(20.30, add);
Copy the code
Of course, it is generally recommended that you use type aliases to define functions
type CalcFn = (n1: number, n2: number) = > number
Copy the code
Interface inheritance
Interfaces, like classes, can be inherited using the extends keyword
And interfaces support multiple inheritance (classes do not)
interface ISwim {
swimming: () = > void;
}
interface IFly {
flying: () = > void;
}
interface IAction extends ISwim, IFly {}
const action: IAction = {
swimming() {},
flying(){}};Copy the code
Interface implementation
Once an interface is defined, it can be implemented by a class
If an interface is implemented by a class, that class can be passed in wherever the interface needs to be passed in later
This is called interface oriented development
Cross type
The union type you learned earlier represents just one of several types
type MyType = number | string
type Direction = "left" | "right" | "center"
Intersection Types There is another type of merge, called Intersection Types.
- Cross similarity means that conditions of more than one type need to be satisfied
- Cross similarity means that conditions of more than one type need to be satisfied
The following cross type satisfies both a number and a string, but it does not, so MyType is actually a never type
type MyType = number & string
Copy the code
So in development, when we do crossovers, we usually do crossovers for object types
interface ISwim {
swimming: () = > void;
}
interface IFly {
flying: () = > void;
}
type MyType1 = ISwim | IFly;
type MyType2 = ISwim & IFly;
const obj1: MyType1 = {
flying(){}};const obj2: MyType2 = {
swimming() {},
flying(){}};Copy the code
Interface is different from type
Interface and type can both be used to define object types, so which one to choose when defining object types in development?
If you are defining non-object types,
- It is recommended to use
type
, such as Direction, Alignment, FunctionIf you define object types, they are different
Interfaces can repeatedly define properties and methods for an interface (equivalent to merging interfaces)
interface IFoo { name: string } interface IFoo { age: number } Copy the code
Type defines an alias, which cannot be repeated
/ / an error type IBar = { name: string age: number } type IBar = { } Copy the code
Literal assignment
TypeScript imposes strict type restrictions for type derivation when assigning literal values directly
If we are assigning a variable identifier to another variable, a freshness erase is performed
interface IPerson {
name: string;
age: number;
height: number;
}
const info = {
name: "why".age: 18.height: 1.88.address: "Guangzhou"};// freshness erases assignment to p erases unnecessary address attributes
const p: IPerson = info;
console.log(info);
console.log(p);
Copy the code
Type erasure occurs when we pass a reference to a function as an argument
function printInfo(person: IPerson) {
console.log(person);
}
const info = {
name: "yun".age: 18.height: 1.88.address: "Guangzhou"}; printInfo(info);Copy the code
The generic
A feature that does not specify a specific type when defining a function, interface, or class, but specifies the specific type when it is used
Generics implement type parameterization
When defining this function, I do not determine the types of these arguments
I’m going to let the caller tell me, in terms of parameters, what type of function arguments should I have here
function sum<Type> (num: Type) :Type {
return num;
}
// Call method 1: pass the type to the function by < type >
sum<number> (20);
sum<{ name: string({} >name: "why" });
sum<any[] > ["abc"]);
Type inference, which automatically extrapolates to the type of the variable we pass in
sum(50);
sum("abc");
Copy the code
Generics accept multiple type parameters
function foo<T.E.O> (arg1: T, arg2: E, arg3? : O, ... args: T[]) {
}
foo<number.string.boolean> (10."abc".true)
Copy the code
You might see some common names in development
- T: short for Type
- K, V: short for key and value, key-value pair
- E: Short for Element
- O: Object
A generic interface
We can also use generics when defining interfaces
Specify default values
interface iFoo<T = number> {
}
Copy the code
Use of generic classes
class Point<T> {
x: T;
y: T;
z: T;
constructor(x: T, y: T, z: T) {
this.x = x;
this.y = y;
this.z = y; }}const p1 = new Point("1.33.2"."2.22.3"."4.22.1");
const p2 = new Point<string> ("1.33.2"."2.22.3"."4.22.1");
const p3: Point<string> = new Point("1.33.2"."2.22.3"."4.22.1");
const names2: Array<string> = ["abc"."cba"."nba"]; // React JSX is not recommended.
const names1: string[] = ["abc"."cba"."nba"];
Copy the code
Generic constraints for a type
Sometimes we want the types passed in to have some commonality, but those commonalities may not be in the same type
For example, string and array have length, or some objects have length
So as long as the length of the property can be used as our parameter type, so how to operate?
interface ILength {
length: number;
}
function getLength<T extends ILength> (arg: T) {
return arg.length;
}
getLength("abc");
getLength(["abc"."cba"]);
getLength({ length: 100 });
Copy the code
Modular development
TypeScript supports two ways to control our scope
- Modularity: Each file can be a separate Module, supporting ES Module as well as CommonJS
- Namespace: A namespace is declared through a namespace
export function add(num1: number, num2: number) {
return num1 + num2;
}
export function sub(num1: number, num2: number) {
return num1 - num2;
}
Copy the code
Namespace namespace
In TypeScript’s early days, namespaces were called internal modules
The main purpose is to divide the scope within a module to prevent some naming conflicts
export namespace time {
export function format(time: string) {
return "2222-02-22";
}
export let name: string = "abc";
}
export namespace price {
export function format(price: number) {
return "99.99"; }}Copy the code
Type declaration
Type lookup
We’ve written almost all of the typescript types in the past, but we also use some other types
Const imageEl = document.getelementById (“image”) as HTMLImageElement;
Where does the HTMLImageElement type come from?
This is where typescript’s rules for managing and finding types come in
Typescript also has another type of file,.d.ts files, that declare what types are available
So where does typescript look for our type declarations?
- Built-in type declaration
- Externally define type declarations
- Externally define type declarations
Built-in objects
There are many built-in objects in JavaScript that can be treated directly as defined types in TypeScript
Built-in objects are objects that exist in the Global scope according to the standard. Standards here refer to ECMAScript and standards in other environments such as DOM
- ECMAScript built-in object
- Boolean
- Number
- String
- Date
- RegExp
- Error
/* 1. ECMAScript built-in objects */
let b: Boolean = new Boolean(1)
let n: Number = new Number(true)
let s: String = new String('abc')
let d: Date = new Date(a)let r: RegExp = / / ^ 1
let e: Error = new Error('error message')
b = true
// let bb: boolean = new Boolean(2) // error
Copy the code
- BOM and DOM built-in objects
- Window
- Document
- HTMLElement
- DocumentFragment
- Event
- NodeList
const div: HTMLElement = document.getElementById('test')
const divs: NodeList = document.querySelectorAll('div')
document.addEventListener('click'.(event: MouseEvent) = > {
console.dir(event.target)
})
const fragment: DocumentFragment = document.createDocumentFragment()
Copy the code
Built-in type declaration
Built-in type declarations are the declarations that come with typescript that help us build in some of the JavaScript runtime’s standardized apis
This includes built-in types such as Math and Date, as well as DOM apis such as Window and Document
Built-in type declarations usually come with typescript installations
- · Microsoft /TypeScript (github.com)
Externally define type declarations
External type declarations are usually used when we use some library (such as third-party library), we need to reference its declaration file, in order to get the corresponding code completion, interface hints and other functions
These libraries typically have two types of declarations:
- Method 1: Make type declarations in your own library (write.d.ts files), such as Axios
- Method 2: A DefinitelyTyped public library of the community stores the type declaration file
- GitHub address for the library: github.com/DefinitelyT…
- The library search statement installation address: www.typescriptlang.org/dt/search?s…
- For example, we install the react type declaration: NPM i@types /react –save-dev
Custom declaration
When do you need to define a declaration file yourself?
- Case 1: The third-party library we use is a pure JavaScript library with no corresponding declaration file. Such as lodash
- Case 2: We declare some types in our code so we can use them directly elsewhere
The statement module
We can also declare modules, such as loDash, if the module is disabled by default. We can declare the module ourselves
Declare module ‘module name’ {}
In the declaration module, we can export the corresponding library classes, functions and so on
declare module "lodash" {
export function join(arr: any[]) :any;
}
Copy the code
Declare variable-function-class
// index.html
let whyName = "coderwhy";
let whyAge = 18;
let whyHeight = 1.88;
function Foo() {
console.log("whyFoo");
}
function Person(name, age) {
this.name = name;
this.age = age;
}
// .d.ts
// Declare variables/functions/classes
declare let whyName: string;
declare let whyAge: number;
declare let whyHeight: number;
declare function whyFoo() :void;
declare class Person {
name: string;
age: number;
constructor(name: string, age: number);
}
Copy the code
Declare declaration file
In some cases, we can also declare files
For example, during vUE development, our.vue files are not recognized by default, so we need to file them
For example, we use image files like.jpg in development, which are not supported by the default typescript and need to be declared
declare module "*.vue" {
import { DefineComponent } from "vue";
const component: DefineComponent;
export default component;
}
declare module "*.jpg" {
const src: string;
export default src;
}
Copy the code
Declare namespace
For example, we introduced jQuery directly in index. HTML
- CDN address: cdn.bootcdn.net/ajax/libs/j…
We can make namespace declarations:
declare namespaceThe ${export function ajax(settings: any) :any;
}
Copy the code
This can be used in main.ts:
$.ajax({
url: "http://123.207.32.32:8000/home/multidata".success: (res: any) = > {
console.log(res); }});Copy the code
Tsconfig. Json file
Tsconfig. json is a configuration option used to configure TypeScript compile-time
TypeScript: TSConfig Reference – Docs on every TSConfig option (typescriptlang.org)
5. Pack TS with Webpack
Download the dependent
yarn add -D typescript
yarn add -D webpack webpack-cli
yarn add -D webpack-dev-server
yarn add -D html-webpack-plugin clean-webpack-plugin
yarn add -D ts-loader
yarn add -D cross-env
Copy the code
#JS: entrance SRC/main. Ts
// import './01_helloworld'
document.write('Hello Webpack TS! ')
Copy the code
#Index page: public/index.html
<! DOCTYPEhtml>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="Width = device - width, initial - scale = 1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>webpack & TS</title>
</head>
<body>
</body>
</html>
Copy the code
#build/webpack.config.js
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const path = require('path')
const isProd = process.env.NODE_ENV === 'production' // Whether the production environment
function resolve (dir) {
return path.resolve(__dirname, '.. ', dir)
}
module.exports = {
mode: isProd ? 'production' : 'development'.entry: {
app: './src/main.ts'
},
output: {
path: resolve('dist'),
filename: '[name].[contenthash:8].js'
},
module: {
rules: [{test: /\.tsx? $/,
use: 'ts-loader'.include: [resolve('src')]}},plugins: [
new CleanWebpackPlugin({
}),
new HtmlWebpackPlugin({
template: './public/index.html'})].resolve: {
extensions: ['.ts'.'.tsx'.'.js']},devtool: isProd ? 'cheap-module-source-map' : 'cheap-module-eval-source-map'.devServer: {
host: 'localhost'./ / host name
stats: 'errors-only'.// Package log output error information
port: 8081.open: true}},Copy the code
#Configuring packaging Commands
"dev": "cross-env NODE_ENV=development webpack-dev-server --config build/webpack.config.js",
"build": "cross-env NODE_ENV=production webpack --config build/webpack.config.js"
Copy the code
#Run and package
yarn dev
yarn build
Copy the code