1. Introduction to TypeScript
1. Characteristics
- Typescript is a language built on top of JavaScript
- A superset of JavaScript
- Cannot be executed directly by JS parser
- Extends JS, and adds types
The relationship between TS, ES6, and JS:
TS online compiler
2. Build the environment
- Download Node
Download address: https://nodejs.org/en/download/
-
Install Node
-
Install typescript globally using npm
npm i typescript -g
Verify that the installation was successful:tsc -v
-
Create a ts file
-
Use tsc to compile the ts file
- enter the command line
- Enter the directory where the ts file is located
- Excuting an order:
tsc greeter.ts
After executing the command, a compiled file will appear in the same directory greeter.js
.
- run js
node greeter.js
-
Simplify the ts running process
Use
ts-node
, you can run the ts file directly. It needs to be installed globally firstnpm i -g ts-node
. Then executets-node greeter.ts
.When ts-node is executed, it converts the ts file into js internally, and then executes the js code;
3. Description of common methods
3.1 keyof
keyof
It Object.keys
is slightly similar to , except that keyof
it takes the key of the object type , and after the key keyof
is taken it will be saved as a joint type .
type Point = {
x: number; y: number };
type P = keyof Point;
//type P = keyof Point 等效
type Arrayish = {
[n: number]: unknown };
type A = keyof Arrayish;
//type A = number 等效
type Mapish = {
[k: string]: boolean };
type M = keyof Mapish;
//type M = string | number 等效
Combined class use:
type Person = {
name: string
age: number
add: string
}
class Student {
constructor(private info: Person) {
}
getInfo<T extends keyof Person>(key: T): Person[T] {
return this.info[key];
}
}
let student = new Student({
name: "IT飞牛", age: 19, add: "上海" });
console.log(student.getInfo("name")); //打印:IT飞牛
Use with generic classes:
class Student<K> {
constructor(private info: K) {
}
getInfo<T extends keyof K>(key: T): K[T] {
return this.info[key];
}
}
let student = new Student({
name: "IT飞牛", age: 19 });
console.log(student.getInfo("name")); //打印:IT飞牛
3.2 in keyof
in
It can be understood that for ... in
it means traversing each type from keyof T
it , using the above example, it is the type of "a"
, and"b"
. "c"
Note that they are not string
type , but literal string
type, which is a specific string type. For example, a variable of "a"
type can only be "a"
a value.
Represents a string literal type, often used in mapping types
type Props = {
a: number; b: number; c: number };
// 映射类型:根据对象类型来创建
type Type3 = {
[key in keyof Props]: number };
3.2 extends keyof
K extend keyof T
Indicates K
that is T
a subtype of , here is a type constraint declaration. For example type T = "a" | "b" | "c";
, then K
can be "a"
, can also be "a" | "c"
or "a" | "b" | "c"
etc.;
Represents a sub-joint type, often used to define a sub-joint type
class Student<K> {
constructor(private info: K) {
}
getInfo<T extends keyof K>(key: T): K[T] {
return this.info[key];
}
}
Two, TypeScript commonly used types
TypeScript is a superset of JS, TS provides all the functions of JS, and additionally adds a type system;
- All js code is ts code
- js has types (for example: number, string, ...), but js does not check whether the type of the variable changes. And TS will check. The main advantage of the TypeScript type system: It can explicitly flag unexpected behavior in the code, thereby reducing the possibility of errors.
1. Type annotations
let age:number=18;
:number
Type annotations are in the code . The role is to add type constraints to variables. Whatever type is agreed upon, only the value of that type can be assigned to the variable, otherwise, an error will be reported.
2. Overview of common basic types
Common basic types in TS can be subdivided into two categories: JS existing types and TS new types .
-
JS already has types:
- Primitive types: string, number, boolean, null, undefined, symbol
- Object type: object (array, object, function, etc.)
-
TS new type
- Union type, custom type (type alias), interface, tuple, literal type, enumeration, any, etc.
2.2 Primitive types
Primitive types: string, number, boolean, null, undefined, symbol
Features: Simple. These types are written exactly according to the names of the types in js.
let flag: boolean = true;
let myname: string = "IT飞牛";
let num: number = 100;
2.3 Array types
Two ways of writing array types:
let numbers:number[]=[1,2,3];
let strings:Array<string>=["a","b","c"];
If there are both number
types and string
types in the array, how should the type of the array be written?
let arr:(number|string)[]=[1,"a",3,"b"];
| (vertical bar) is called a joint type in TS (a type composed of two or more other types, indicating that it can be any of these types).
2.4 Type aliases
Type Alias (Custom Type): Alias any type.
Usage scenario: When the same type (complex) is used multiple times, the type alias can be used to simplify the use of this type.
type CustomArray=(number|string)[];
let arr1:CustomArray=[1,"a",3,"b"];
let arr2:CustomArray=["x","y",6,7];
explain:
- Use the type keyword to create type aliases
- A type alias (for example, CustomArray here), can be any legal variable name.
- After creating a type alias, you can directly use the type alias as the type annotation of the variable.
2.5 Function types
The type of a function actually refers to: the type of function parameters and return value.
There are two ways to specify a type for a function:
- Separately specify the type of parameters and return values
function add(num1: number, num2: number): number {
return num1 + num2;
}
const add = (num1: number, num2: number): number => {
return num1 + num2;
}
- Specify the type of parameters and return value at the same time
const add : (num1: number, num2: number) => number = (num1, num2) => {
return num1 + num2;
}
When a function is an expression, you can add a type to the function through a syntax similar to the arrow function form. This form works only with function expressions.
If the function does not return a value, then the function return value type is: void
.
function greet(name:string):void{
console.log("Hello",name);
}
When using a function to implement a function, parameters can be passed or not. In this case, optional parameters are used when specifying a type for a function parameter. For example, slice
the method of the array, can slice()
also be slice(1)
, can also be slice(1,3)
.
function mySlice(start?:number,end?:number):void{
console.log("起始索引:",start,"结束索引:",end);
}
Optional parameters: Add ? after the name of optional and non-optional parameters (question mark)
Optional parameters can only appear at the end of the parameter list, that is to say, mandatory parameters cannot appear after optional parameters.
Functions with rest parameters:
function add(...nums: number[]) {
let sum = 0;
sum = nums.reduce((a, b) => {
return a + b;
})
console.log(sum);
}
add(1, 2, 3); //打印:6
2.6 Object types
Objects in JS are composed of properties and methods, and the type of objects in TS is to describe the structure of the object (what types of properties and methods are there).
The writing method of object type:
let person: {
name: string; age: number; sayHi(): void } = {
name: 'IT飞牛',
age: 19,
sayHi() {
}
}
- Use directly
{}
to describe object structures. The form an attribute takes属性名:类型
;方法名():返回值类型
the form a method takes. - If the method has parameters, specify the parameter type in parentheses after the method name (for example:
greet(name:string):void
). - When specifying multiple property types of an object in one line of code, use
;
(semicolon) to separate them. - If a line of code specifies only one attribute type (multiple attribute types are separated by newlines), you can remove
;
(semicolon) - The type of the method can also use the arrow function form (for example:
{sayHi:()=>void}
)
The properties or methods of an object can also be optional, and optional properties are used at this time.
For example: when we use it axios({...})
, if we send a GET request, the method attribute can be omitted.
function myAxios(config:{
url:string;method?:string}){
console.log(config);
}
The syntax of optional attributes is the same as that of optional parameters of functions, which are ?
represented by (question mark).
2.7 Interface
When an object type is used multiple times, an interface is generally used (interface)
to describe the type of object to achieve the purpose of reuse.
- Use
interface
keywords to declare interfaces - Interface name (for example: here
IPerson
), can be any legal variable name - After declaring an interface, use the interface name directly as the type of the variable.
- Because there is only one attribute type per line, there is no
;
(semicolon) after the attribute type
interface IPerson{
name:string
age:number
sayHi():void
}
let person:IPerson={
name:"IT飞牛",
age:19,
sayHi(){
}
};
Comparison of interface and type:
The same point: both can specify types for objects
difference:
- Interface: Types can only be specified for objects.
- Type aliases: Not only can you specify types for objects, but you can actually specify aliases for any type.
interface IPerson {
name: string
age: number
sayHi(): void
}
type IPerson{
name: string
age: number
sayHi(): void
}
type NumStr = number | string
If there are the same properties or methods between the two interfaces, the public properties or methods can be extracted and reused through inheritance.
For example, both interfaces have x、y
these two attributes, repeating these two times will be very complicated.
//改造前
interface Point2D {
x: number, y: number }
interface Point3D {
x: number, y: number, z: number }
//改造后
interface Point2D {
x: number, y: number }
interface Point3D extends Point2D {
z: number }
- Interface inheritance
extends
is achieved using the (inherit) keyword .Point3D
Point2D
- After inheritance,
Point3D
there arePoint2D
all properties and methods (at this time,Point3D
there arex、y、z
three properties at the same time).
2.8 tuples
On the map, location information is marked using latitude and longitude coordinates.
An array can be used to record the coordinates. Then, there are only two elements in the array, and both elements are of numeric type.
let position:number[]=[39.3213,116.3123];
Disadvantages of use number[]
: not rigorous, because any number of numbers can appear in this type of array. A better way: Tuple
A tuple type is another type of array that knows exactly how many elements it contains, and which type a particular index corresponds to.
let position: [number, number] = [1.1, 2.3];
2.9 Type inference
In TS, where the type is not clearly indicated, TS's type inference mechanism will help provide the type.
In other words: Due to the existence of type inference, type annotations can be omitted in these places!
There are two common scenarios where type inference occurs:
- When declaring a variable and initializing
//鼠标移入age,TS自定推断出变量age为number类型
let age=18;
- When determining the return value of a function
//鼠标移入add,系统自动推断函数返回值是number类型
function add(num1:number,num2:number){
return num1+num2;
}
In both cases, type annotations can be omitted!
Recommendation: omit the type annotation where it can be omitted (lazy, make full use of the ability of TS type inference to improve development efficiency)
Tip: If you don’t know the type, you can place the mouse on the variable name and use VSCode’s prompt to view the type.
2.10 Type Assertions
Sometimes you will be more specific about the type of a value than TS. At this time, you can use type assertion to specify a more specific type.
<a href="https://blog.csdn.net/bobo789456123" id="link">IT飞牛</a>
//此时类型推断会识别alink的类型为:HTMLElement
const alink=document.getElementById("link")
alink
At this time, the type that type inference will recognize is HTMLElement
that this type only contains attributes or methods common to all tags, and does not contain a
tag-specific href
attributes.
Therefore, this type is too broad to operate on attributes or methods specific to href
such a
tags.
//这两个写法等效
const alink = document.getElementById("link") as HTMLAnchorElement
const alink=<HTMLAnchorElement>document.getElementById("link")
- Use
as
keywords to implement type assertions - The type following the keyword
as
is a more specific type ( subtype of yes.HTMLAnchorElement
)HTMLElement
2.11 Literal types
Think about the code, what are the types of the two variables?
let str1="Hello feiniu";
const str2="Hello IT";
Through the TS type inference mechanism, the answer that can be obtained:
- The variable str1 is of type
string
- The variable str2 is of type
Hello IT
str2 is a constant, its value cannot be changed
Hello IT
, so its type isHello IT
.
Note: here Hello IT
is a literal variable. That is to say, a specific string can also be used as a type in TS. In addition to strings, any JS literal (such as: object, number, etc.) can be used as a type.
**Common usage scenarios:** Used to represent a list of explicit set of optional values. Often used with union types.
function changeDirection(direction:"up"|"down"|"left"|"right"){
console.log(direction);
}
Note:
direction
The value of the parameter can only beup/down/left/right
any one of them.Advantages: Compared with
string
types, using literal types is more precise and rigorous.
2.12 Enumeration
The function of the enumeration is similar to the function of the combination of literal type + union type, and can also represent a clear set of optional values.
Enum: Defines a set of command constants. It describes a value, which can be one of these named constants.
2.12.1 Numeric enumerations
//使用联合类型+字面量类型
function changeDirection1(direction: Direction1) {
console.log(direction);
}
type Direction1 = "up" | "down" | "left" | "right";
changeDirection1("up");
// 使用枚举
function changeDirection2(direction: Direction2) {
console.log(direction);
}
enum Direction2 {
Up, Down, Left, Right };
changeDirection2(Direction2.Up);
enum
Defining enumerations using keywords- Convention enumeration name, value in the enumeration starts with uppercase and lowercase letters
- Multiple values in an enumeration are
,
separated by (commas) - After defining the enumeration, use the enumeration name directly as the type annotation
Direction2
Each enumeration value is not specified in, and the default is a numeric enumeration. For example, the following Direction2.Up
is passed in as an actual parameter, and its value is 0. That is to say, the enumeration members have values, and the default value is an auto-increment value from 0 .
We can also initialize values in enums.
function changeDirection2(direction: Direction2) {
console.log(direction);
}
enum Direction2 {
Up = 2, Down = 4, Left = 6, Right };
changeDirection2(Direction2.Up); //值为2
changeDirection2(Direction2.Right); //值为7
2.12.2 String enumeration
The values of enumeration members are strings.
function changeDirection2(direction: Direction2) {
console.log(direction);
}
enum Direction2 {
Up = "UP", Down = "DOWN", Left = "LEFT", Right="RIGHT" };
changeDirection2(Direction2.Up); //值为UP
changeDirection2(Direction2.Right); //值为RIGHT
String enumerations have no auto-increment behavior, so each member of a string enumeration must have an initial value.
Enums are one of the few features of TS that does not extend JavaScript at the type level (not just types).
Because other types are only treated as types, enumerations are not only used as types, but also provide values (enumeration members all have values)
That is, other types are automatically removed when compiling to JS code. However, enum types are compiled to JS code!
//编译前
enum Direction2 {
Up = "UP", Down = "DOWN", Left = "LEFT", Right="RIGHT" };
//编译后
var Direction2;
(function (Direction2) {
Direction2["Up"] = "UP";
Direction2["Down"] = "DOWN";
Direction2["Left"] = "LEFT";
Direction2["Right"] = "RIGHT";
})(Direction2 || (Direction2 = {
}));
Explanation: Enumeration is similar to the function of the combination of literal type + joint type mentioned above, and is used to represent a clear set of optional value lists.
In general, it is recommended to use the combination of literal type + joint type, because this method is more intuitive, concise and efficient than enumeration.
2.13 any type
Any is not recommended!
This makes TypeScript become AnyScript
(lose the advantage of TS type guards). Because when the type of the value is Any
Yes, any operation can be performed on the transformation, and there will be no code prompt.
let obj: any = {
x: 0 };
obj.bar = 100;
obj();
const s: number = obj;
Other implicitly typed any
cases:
- Declare a variable without providing a type nor a default value
- function parameter without type
2.14 typeof
typeof
As we all know, operators are provided in JS to obtain the type of data in JS.
console.log(typeof "Hello IT飞牛");//打印:string
TS also provides typeof
operators: types that can refer to variables or properties in a type context (type queries).
Usage scenario: According to the value of an existing variable, obtain the type of the value to simplify type writing.
let p = {
x: 1, y: 2 };
function formatPoint1(point: {
x: number, y: number }) {
}
function formatPoint2(point: typeof p) {
} //在类型注解上下文中使用typeof
// 以下两种写法等效
formatPoint1(p);
formatPoint2(p);
Three, TypeScript advanced type
There are many advanced types in TS, focus on learning advanced types:
- class class
- type compatibility
- cross type
- Generics and keyof
- Index signature type and index query type
- mapping type
1. class class
TypeScript fully supports the keywords introduced in ES2015class
, and adds type annotations and other syntax (such as: visibility modifiers, etc.)
class Person {
age: number
gender: string
constructor(age: number, gender: string) {
this.age = age;
this.gender = gender;
}
}
let person = new Person(19, "hello");
- Members are initialized, such as:
age:number
After that, they can bethis.age
accessed through instance members. - A type annotation needs to be specified for the constructor, otherwise it is implicitly inferred
any
; the constructor does not need to return a value type.
class Point {
x: number
y: number
scale(n: number): void {
this.x *= n;
this.y *= n;
}
}
Explanation: Method type annotations (parameters and return values) are the same as function usage.
Two methods of class inheritance:
extends
Inherit parent class (available in ES6)implements
Implement the interface (provided in TS)
1.1 extends inherits the parent class
class Animal {
move() {
console.log("move along");
}
}
class Dog extends Animal {
bark() {
console.log("汪");
}
}
const dog = new Dog();
dog.move();
dog.bark();
//打印:
// move along
// 汪
-
extends
Inheritance through keywords -
If the subclass
Dog
inherits the parent classAnimal
, thenDog
the instance objectdog
has all the properties and methods of the parent classAnimal
and the subclass at the same time.Dog
1.2 Simulating multiple inheritance
TypeScript does not support multiple inheritance, that is, it does not support
class A extends B,C{...}
such writing.
This is done because multiple integrations can potentially increase the complexity of the program.
For exampleB
,C
there aremove()
methods in , andA
the instance of ,move()
there will be ambiguity when calling the method, and you don't know which one to call;
There are two ways to implement multiple integration in ts:
- mix
- inherit class + implement interface
mix:
class B {
breath(): string {
return "i am breath";
}
}
class C {
fly(): string {
return "i am fly";
}
}
class A implements B, C {
breath: () => string;
fly: () => string;
}
//混合
function Mixins(targetClass: any, baseClass: any[]) {
baseClass.forEach(item => {
Object.getOwnPropertyNames(item.prototype).forEach(name => {
if (name != "constructor") {
targetClass.prototype[name] = item.prototype[name];
}
})
});
}
Mixins(A, [B, C]);
let a = new A();
console.log(a.breath());
console.log(a.fly());
// 执行时,需要关闭tsconfig.json中强制初始化校验,否则程序执行失败。
//compilerOptions.strictPropertyInitialization=false
// 打印如下:
// i am breath
// i am fly
inherit class + implement interface
class Person1 {
age: number
gender: string
constructor(age: number, gender: string) {
this.age = age;
this.gender = gender;
}
}
interface Person2 {
high: number;
address: string;
}
class Person extends Person1 implements Person2 {
high: number;
address: string;
constructor(age, gender, high, address) {
super(age, gender);
this.high = high;
this.address = address;
}
}
let person = new Person(29, "hello", 165, "上海市");
console.log(person)
//打印: Person { age: 29, gender: 'hello', high: 165, address: '上海市' }
1.3 implements realize the interface
interface Animal {
move(): void
}
class Dog implements Animal {
move() {
console.log("move along");
}
bark() {
console.log("汪");
}
}
const dog = new Dog();
dog.move();
dog.bark();
//打印:
// move along
// 汪
Let the interface be implemented by
implements
keywordclass
Person类
Implementing an interfaceSingable
means that all methods and properties specifiedPerson类
in must be available in .Singable接口
1.4 Class member visibility
Class member visibility: You can use TS to control whether class
a method or property is class
visible to external code.
Visibility modifiers include:
- public: shared
- private: private
- protected: protected
1.4.1 public
Indicates shared, public, shared members can be accessed anywhere, default visibility.
class Animal {
public move(){
console.log("move along");
}
}
- Add keywords in front of class properties or methods
public
to modify the property or method is common - Because
public
it is the default visibility, it can be omitted directly.
1.4.2 protected
Indicates that it is protected and is only visible in the class and subclasses (non-instance objects) where it is declared.
class Animal {
protected move(){
console.log("move along");
}
}
class Dog extends Animal {
bark() {
this.move();
console.log("汪");
}
}
const dog = new Dog();
dog.bark();
// dog.move(); 会报错
//打印:
// move along
// 汪
- Add keywords in front of class properties or methods
protected
to modify properties or methods that are protected. this
The protected members of the parent class can be accessed inside the methods of the subclass , but they are not visible to the instance.
1.4.3 private
Represents private, intended to be visible in the current class, and invisible to instance objects and subclasses.
class Animal {
private move() {
console.log("move along");
}
protected go() {
this.move();
}
}
class Dog extends Animal {
bark() {
// this.move(); 会报错
this.go();
console.log("汪");
}
}
const dog = new Dog();
dog.bark();
// dog.move(); 会报错
- Add keywords in front of class properties or methods
private
to modify the property or method as private. - Private properties or methods are only visible in the current class, and are invisible to subclasses and instance objects!
1.4.4 readonly
In addition to the visibility modifier, there is another common modifier: readonly
(read-only modifier).
readonly: Indicates read-only, which is used to prevent the assignment of properties outside the constructor value.
class Person {
readonly age: number = 18
constructor(age: number) {
this.age = age;
}
}
let person = new Person(19);
console.log(person.age);
// person.age = 20; 报错
// console.log(person.age);
- Using
readonly
keywords to modify this attribute is read-only. Note that only attributes can be modified and methods cannot be modified. - Note: If
age
the type annotation (for example, herenumber
) after the attribute is not added, theage
type of the attribute is 18 (literal type). - Interfaces, or
{}
object types represented, can also be usedreadonly
.
1.5 Use of get and set
class Company {
// 记住 你要使用的名字的话 前面必须要加上_
private _fullName: string;
//get 的用法
get fullName(): string{
// 函数后(): string 这个的意思是 要求函数返回的类型必须是 string
return this._fullName;
}
// set 的用法
set fullName(newName: string) {
console.log("这里可以写一些你想要的操作的方法");
this._fullName = newName;
}
}
// 执行class
const c = new Company();
c.fullName = "我是小白";
2. Type Compatibility
Two types of systems:
- Structural Type System (structural type system)
- Normal Type System (indicates the type system)
TS uses a structured type system, also known as duck typing (duck type), and type checking focuses on the shape that a value has.
2.1 Class Compatibility
That is, in a structural type system, two objects are considered to be of the same type if they have the same shape. The following variable is defined p
as Point
a type, but its value is Point2D
an instance of , and there is no type error.
class Point {
x: number
y: number
}
class Point2D {
x: number
y: number
}
let p: Point = new Point2D();
Because TS is a structured type system, it only checks
Point
whetherPoint2D
the structure of and is the same (the same, both havex
andy
two attributes, and the attribute types are also the same).If it is in the Norinal Type System (for example, C#, Java, etc.), they are different classes and the types are not compatible.
Note: In a structured type system, it is not accurate to say that two objects are considered to be of the same type if they have the same shape.
A more prepared statement: For object types, y
the members of at least the x
same as and are x
compatible y
(more members can be assigned to fewer).
The following assignments are possible:
class Point {
x: number
y: number
}
class Point2D {
x: number
y: number
}
class Point3D {
x: number
y: number
z: number
}
let point1: Point = new Point2D();
let point2: Point = new Point3D();
In class
addition, other types in TS are also compatible with each other, including interface compatibility, function compatibility, etc.
2.2 Interface Compatibility
Compatibility between interfaces is similar to class
, and class
can interface
also be compatible with.
interface Point {
x: number;
y: number;
}
interface Point2D {
x: number;
y: number;
}
let p1: Point = {
x: 1, y: 2 };
let p2: Point2D = p1;
interface Point3D {
x: number;
y: number;
z: number;
}
let p3: Point3D = {
x: 1, y: 2, z: 3 }
p2 = p3;
class Point3D {
x: number;
y: number;
z: number;
}
let p4: Point2D = new Point3D();
2.3 Function Compatibility
The compatibility between functions is more complicated, and it needs to consider the number of parameters, parameter types, and return value types.
2.3.1 Number of parameters
type F1=(a:number)=>void
type F2=(a:number,b:number)=>void
let f1:F1
let f2:F2=f1;
const arr=["a","b","c"];
arr.forEach(()=>{
})
arr.forEach((item)=>{
})
- Less parameters can be assigned to more parameters, so f1 can be copied to f2
forEach
The first parameter of the array method is a callback function, and the type in this example is:(value:string,index:number,array:string[])=>void
- It is actually very common to omit unused function parameters in JS, and this way of usage contributes to the compatibility between function types in TS.
- And because the callback function has a type, TS will automatically deduce
item/index/array
the type of the parameter
2.3.2 Parameter types
Parameter types at the same position must be the same (primitive type) or compatible (object type).
type F1=(a:number)=>void
type F2=(a:number,b:number)=>void
let f1:F1
let f2:F2=f1;
Function types F2
are compatible with function types F1
because the first argument of F1
and is of the same type.F2
interface Point2D {
x: number
y: number
};
interface Point3D {
x: number
y: number
z: number
};
type F2 = (p: Point2D) => void
type F3 = (p: Point3D) => void
let f2: F2
let f3: F3 = f2
f2 = f3
- This conflicts with the interface compatibility mentioned earlier
- Skill: Disassemble the object and regard each attribute as a parameter, then the one with less parameters
f2
can be assigned to the one with more parametersf3
.
2.3.3 Return value type
If the return value is a primitive type, the two types must be the same at this time, such as F5
andF6
type F5=()=>string
type F6=()=>string
let f5:F5
let f6:F6=f5;
If the return value type is an object type, the one with more members can be assigned to the one with fewer members, such as F7
andF8
type F7 = () => {
name: string }
type F8 = () => {
name: string, age: number }
let f7: F7
let f8: F8
f7 = f8;
3. Crossover type
The cross-type function is similar to interface inheritance extends , which is used to combine multiple types into one type (often used for object types).
interface Person{
name:string}
interface Contact{
phone:string}
type PersonDetail=Person & Contact
//type PersonDetail={name:string;phone:string}; 等同于上方
let obj:PersonDetail={
name:"IT飞牛",
phone:"13312332123"
};
After using the intersection type, the new type PersonDetail
has all the attribute types of Person
and at the same time.Contact
Comparison of cross-type and interface inheritance:
- The same point: both can realize the combination of object types
- The difference: when the two methods implement type combination, the methods for handling type conflicts between attributes with the same name are different.
interface A {
fn: (val: number) => string
}
interface B extends A {
// fn: (val: string) => string 出现同名方法或属性会报错
}
interface C {
fn: (val: string) => string
}
type D = A & C; //交叉类型中,同名属性或者方法不会报错
4. Generics
Generics allow functions to work with multiple types on the premise of ensuring type safety, so as to achieve reuse. It is often used in: functions, interfaces, and classes.
For example:
function id<Type>(value: Type): Type {
return value;
}
console.log(id<number>(100)); //打印:100
// console.log(id(100)); 等效
console.log(id<string>("Hello")); //打印:Hello
// console.log(id("Hello"));等效
- Syntax: Add (angle brackets) after the function name
<>
, and add type variables in angle brackets, such as hereType
. - A type variable
Type
is a special type of variable that deals with types rather than values. - The type variable is equivalent to a type container, which can capture the type provided by the user (the specific type is specified by the user when calling the function).
- Because
Type
it is a type, it can be used as the type of function parameters and return values, indicating that the parameters and return values have the same type. - Type variable
Type
, which can be any legal variable name.
When the compiler cannot infer the type or the inferred type is inaccurate, it needs to explicitly pass in the type parameter, which cannot be omitted
<>
. like:id<number>(100)
4.1 Generic constraints
By default, the type variable of a generic function Type
can represent more than one type, which makes it impossible to access any properties. For example: id("a")
Get the length of the parameter when calling the function.
function id<Type>(value:Type):Type{
console.log(value.length);//报错,不能保证value上有length属性
return value;
}
At this time, you need to use generic constraints to shrink the type.
4.1.1 Specifying more specific types
function id<Type>(value:Type[]):Type[]{
console.log(value.length);
return value;
}
Specify that the input is Type[]
an array, as long as it is data, it must have length
attribute values.
4.1.2 Add constraints
- Creates an interface describing constraints
ILenght
that requireslength
properties. - Using the interface via
extends
keywords, adds constraints to generics (type variables). - This constraint means: The type passed in must have
length
properties. (For example, arrays havelength
attributes and can be passed in normally)
interface ILength {
length: number }
function id<Type extends ILength>(value: Type): Type {
console.log(value.length);
return value;
}
Generic type variables can have multiple types, and type variables can also be constrained (for example, the second type variable is constrained by the first type variable).
For example: Create a function to get the value of a property in an object:
function getProp<MyType, MyKey extends keyof MyType>(obj: MyType, key: MyKey) {
return obj[key];
}
let person = {
name: "IT飞牛", age: 19 };
console.log(getProp(person, "name"));
- A second type variable is added
MyKey
, separated by,
a comma. keyof
Keyword takes an object type, yielding a union type whose key names (which may be strings or numbers) are.- In this example,
keyof Type
what is actually obtained isperson
all the union types built by the object, that is:'name'|'age'
. - The type variable
MyKey
isMyType
constrained, which can be understood as:MyKey
it can only beMyType
any one of all keys, or it can only access the properties that exist in the object.
4.2 Generic interfaces
Interfaces can also be used with introspection to increase its flexibility and enhance its reusability.
interface IdFunc<MyType> {
id: (value: MyType) => MyType
ids: () => MyType[]
}
let obj: IdFunc<number> = {
id(value) {
return value; },
ids() {
return [1, 3, 5]; }
}
Remark:
- Add after the interface name
<类型变量>
, then this interface becomes a generic interface. - The type variable of the interface is visible to all other members of the interface, that is, all members of the interface can use the type variable.
- When using a generic interface, it is necessary to specify a specific type (for example: here is
IdFunc<number>
) - At this time,
id
the parameter and return value types of the method arenumber
;ids
the return value type of the method isnumber[]
;
In fact, the array in Js is a generic interface in TS. When we use different types of arrays, TS will automatically set the type variable to the corresponding type according to the different types of arrays.
4.3 Generic classes
class组件
For example, the base class of React is a generic class, and Component
different components have different sums .props
state
4.4.1 Creating generic classes
- Similar to a generic interface, by
class
adding it after the name<类型变量>
, the class becomes a generic class. - The method here
add
adopts the type writing method in the form of arrow function.
class genericNumber<NumType>{
defaultValue: NumType
add: (x: NumType, y: NumType) => NumType
}
const myNum = new genericNumber<number>();
myNum.defaultValue = 10;
console.log(myNum.defaultValue);
ts-node greeter.ts
When the above code is executed directly , there will be a promptdefaultValue
andadd
no initialization, becausetsconfig.json
initialization is required by defaultcompilerOptions.strictPropertyInitialization=true
. But doing so is not recommended.
There are three ways to circumvent:
-
Use a non-empty assertion, add after the attribute
!
:defaultValue!: NumType
-
Use union types.
defaultValue: NumType | null | undefined
-
To use optional attributes, add " after the attribute
?
:defaultValue?: NumType
4.4 Generic tool types
Some commonly used tool types are built into TS to simplify some common operations in TS.
Explanation: They are all implemented based on generics (generics are applicable to multiple types and are more general), and they are built-in and can be used directly in the code.
There are many types of these tools, mainly the following:
Partial<Type>
: Used to construct a type, andType
set all properties of it to optional
interface Person {
id: string
children: number[]
}
type PartialProps = Partial<Person>;
Readonly<Type>
: Used to construct a type andType
set all properties of it to read-only
interface Person {
id: string
children: number[]
}
type PartialProps = Readonly<Person>;
Pick<Type,Keys>
: Select a set of propertiesType
from which to construct a new type.
//Pick工具类型有两个类型变量:1、表示选择谁的属性 2、表示选择哪几个属性
//第二个类型变量,如果只选择一个则只传入该属性名即可。且只能是第一个类型变量中存在的属性
//构造出来的新类型PickProps,只有id和title两个属性类型。
interface Props {
id: string
title: string
children: number[]
}
type PickProps = Pick<Props, "id" | "title">;
Record<Keys,Type>
: Constructs an object type with property keykeys
and property typeType
.
//Record工具类型有两个类型变量:1、表示对象有哪些属性 2、表示对象属性的类型
//构建的新对象类型RecordObj表示:这个对象有三个属性类型分别为a/b/c,属性值的类型都是string[];
type RecordObj = Record<"a" | "b" | "c", string[]>;
let obj: RecordObj = {
a: ["1"], b: ["2"], c: ["3"] };
//下面指定一个键类型是number,值类型时string的对象
let arg4: Record<number, string> = {
1: "a",
2: "b",
3: "c",
};
5. Index signature type
Arrays are a special type of object in JS, especially in that the keys (indexes) of the array are numeric types.
Also, an array can have any number of elements. Therefore, the index signature type is also used in the generic interface corresponding to the array.
interface MyArray<T> {
[n: number]: T
}
let arr: MyArray<number> = [1, 3, 5];
Remark:
MyArray
The interface mimics the native array interface and uses[n:number]
as the index signature type.- The index signature type indicates that any
number
type of key (index) can appear in the array, or there can be any number of elements in the array. - It also meets
number
the premise that the array index is a type. T
is generic.
6. Mapping type
Mapping types: create new types (object types) based on old types, reduce repeated development, and improve development efficiency.
For example: a type PropKeys
has x/y/z in x/y/z
another type Type1
, and the types Type1
in x/y/z
are the same.
type PropKeys = "x" | "y" | "z";
// 传统写法
type Type1 = {
x: number, y: number, z: number };
// 映射类型
type Type2 = {
[key in PropKeys]: number };
- The mapping type is based on the index signature type, so the syntax is similar to the index signature type, also using
[]
Key in PropKeys
Indicates that any one of the s union typesKey
can be made, similar toPropKey
forin(lei k in obj)
Type2
New object types andType1
structures created using mapped types are exactly the same- Note: Mapped types can only be used in type aliases, not interfaces
type Props = {
a: number; b: number; c: number };
// 映射类型:根据对象类型来创建
type Type3 = {
[key in keyof Props]: number };
Remark:
- First, execute the union type
keys Props
that getsProps
all the keys in the object type:“a”|"b"|"c"
- Then,
Key in ...
it meansKey
that it can beProps
any one of all the key names in .
In fact, the generic tool types mentioned above (for example:
Partial<Type>
) are all implemented based on the mapping type
For example, Partial<Type>
the implementation of:
type Partial<T> = {
[P in keyof T]: T[P]
}
type Props = {
a: number; b: number; c: boolean }
type PartialProps = Partial<Props>
4. Type declaration file
Type declaration files are used to provide type information for existing JS libraries. In this way, when using these libraries in TS projects, just like using TS, there will be mechanisms such as code hints and type protection.
1. Two file types in TS
1.1 .ts
Documentation
- Contains both type information and executable code
- Can be compiled into a .js file and then execute the code
1.2 .d.ts
Documentation
- A type declaration file that contains only type information
- No .js files will be generated, only used to provide type information
.ts
It is a code implementation file;.d.ts
it is a type declaration file;If you want to provide type information to a JS library, use
.d.ts
a file.
2. Instructions for use of the type declaration file
2.1 Using an existing type declaration file
2.1.1 Built-in type declaration files
TS provides declaration files for all standardized built-in APIs available to the JS runtime.
For example, when using an array, all methods of the array will have corresponding code hints and type information:
in fact, these are built-in type declaration files provided by TS. You can view the content of built-in type files by pressing Ctrl+left mouse button .
2.1.2 The type declaration file of the third-party library
Almost all commonly used third-party libraries have corresponding type declaration files. There are two forms:
- The library comes with type declaration files, such as
axios
DefinitelyTyped
provided by
DefinitelyTyped
is a github repository for high-quality TypeScript type declarations.
You can npm/yarn
download the TS type declaration packages provided by this repository through . The format of these packages is: @types/ *. For example: @types/react
, @types/lodash
etc., when @types/*
the type declaration package is installed, TS will also automatically load the type life package to provide the type declaration of the modified library.
In actual project development, if the third-party library you use does not have its own declaration file, VSCode will give a clear prompt.
The TypeScript official website provides @types/*
the query address of the library: Type Search
2.2 Create your own type declaration file
2.2.1 Shared types within a project
If .ts
the same type is used in multiple files, you can create .d.ts
a file to provide the type at this time to achieve type sharing.
Steps:
- Create
index.d.ts
a type declaration file - Create types that need to be shared and use export to export (types in TS can also use import/export to achieve modular functions)
- In the file that needs to use the shared type
.ts
,import
it can be imported (.d.ts
when the suffix is imported, it is directly omitted).
2.2.2 Provide type declarations for existing JS files
- When migrating JS projects to TS projects, in order to allow existing
.js
files to have type declarations. - Become a library author and create libraries for others to use.
Files are also available in TS projects .js
. When importing .js
a file, TS will automatically load the file with .js
the same name .d.ts
, and the type declaration has been provided.
declare
Keyword: Used for type declarations, .js
declaring types for variables that already exist in other places (such as files) instead of creating a new variable.
- For
type
,interface
etc., these are clearly of the TS type, anddeclare
keywords can be omitted. - For
let
,function
and so on have double meanings (js and ts are both available),declare
keywords should be used to clearly specify that this is used for type declaration.