A prelude to
TypeScript is essential for project development to standardize JS types. This article mainly summarizes the basic knowledge of TypeScript. (PROJECTS without TypeScript are like milk tea without milk, hahaha.)
Summary of TypeScript
Before I introduce you, why use TypeScript?
JS is a scripting language. As a parsing language, it can only find errors at run time. It is a weakly typed language.
TS is a superset of JS that can be corrected during compilation to address code complexity in large projects. Support for strong typing, static typing, support for modules, interfaces and generics, eventually compiled into JS code for browser use.
TS helps us detect type definition problems in our code at development time, greatly enhancing the readability and maintainability of our code.
The installation of the TypeScript
-
The installation
npm install -g typescript Copy the code
-
validation
tsc -v Copy the code
-
compile
tsc hello.ts Copy the code
This command generates a hello.js file
Note:
- Ts must be compiled into a JS file before it can be executed.
- Ts checks the type only at compile time. If any errors are found, an error is reported at compile time. At runtime, the generated JS file does not undergo type checking, just like regular JS files.
TypeScript base types
-
Boolean type
let isDone: boolean = false; // es6 let isDone = false; Copy the code
-
The number type
let age:number = 18; // es6 let age = 18; Copy the code
-
Type string
let str:string = 'xiaoqi'; // es6 let str = 'xiaoqi'; Copy the code
-
Symbol type
const sym = Symbol(); let obj = { [sym]: "value" }; console.log(obj[sym]); // "value" Copy the code
-
Array an Array
There are two representations: one is: element type +[]; The other is Array generics: Array< element type >
let list:number[] = [1.2.3]; let list1: Array<number> = [4.5.6]; // es6 let list = [1, 2, 3]; // es6 let list1 = [4, 5, 6]; Copy the code
-
The Tuple type
The Tuple type is unique to TS, similar to arrays, but it specifies the type at each location.
let tuple:[string,number,string,boolean] = ['xiaoqi'.20.Love front end,true] Copy the code
An error occurs if the initialized type does not match the specified type.
-
Enum Type Enum Enum Enum types are a group of values, which can be semantic, such as the definition of various status codes.
enum Color { red, green, bule } let color:Color = Color.red; console.log(color); / / 0 Copy the code
By default, values start at 0 and are assigned in sequence. It can also be assigned manually:
enum Color { red = 4, green, bule } let color:Color = Color.green; console.log(color); / / 5 Copy the code
This assigns values from 5, or all of them manually:
enum Color { red = 4, green = 9, blue = 12,}let color:Color = Color.blue; console.log(color); / / 12 Copy the code
Enumeration types support reverse mapping from member name to member name in addition to mapping from member name to member value.
enum Color { red = 4, green = 9, blue = 12,}let color:Color = Color.blue; console.log(color); / / 12 let colorName: string = Color[9]; console.log(colorName); // "green" Copy the code
Enumeration types also support member values that are a mixture of numbers and strings:
enum Enum { A, / / 0 B, / / 1 C = "C", D = "D", E = 8, F / / 9 } Copy the code
-
Any type
If the type of the variable is not known at compile time, it can be marked with the any type. The use of any avoids ts type detection and is generally not recommended.
let value:any; value.trim(a); value(); value[0][1]; Copy the code
None of this code will report an error after the value type is defined as any. And values of type any can be assigned to values of other types (top-level types).
let value:any = 123; let num:number = value; Copy the code
-
UnKnown type
A value of any type can be assigned to a variable of type any, and a value of any type can be assigned to a variable of type unknown. The difference is that the unknown type cannot be assigned to variables of other types. It can only be assigned to any and unknown types.
let value2:unknown = 4; value2 = true; value2 = "hello"; value2 = []; value2 = undefined; value2 = null; Copy the code
The above code is ok, and any type value can be assigned to unknown type.
let value: any = 10; let value2:unknown = 10; let value3: unknown = "hello"; let num:number = 4; num = value; // ok num = value2; // Error unknown Types cannot be assigned to types other than any and unknown value = value2;// ok unknown type assigned to any type value3 = value2; // ok assign unknown type to unknown type Copy the code
-
In TypeScript, undefined and null have their own types called undefined and NULL, respectively.
let u: undefined = undefined; let n: null = null; let conter:void; conter = u; console.log(conter);// undefined Copy the code
When strictNullChecks is specified, null and undefined can only be assigned to void and their respective checks.
-
Never type The never type represents the types of values that never exist. No type can be assigned to never. Two cases in which a value does not exist: the function throws an exception, for example, or the function never completes (an infinite loop).
function errorFunction() :never { throw new Error(a);// After an exception is thrown, the execution cannot be completed console.log('hello'); } function forNever() :never { while(true) {};// The console below is never executed console.log('hello'); } Copy the code
-
Void type
In a way, void is the opposite of any in that it means there is no type. When a function returns no value, its return value type is void.
function user() :void { console.log('hello'); // If an additional return value is added, an error is reported } Copy the code
A void variable can only be assigned to undefined and null. StrictNullChecks when strictNullChecks is not specified as true.
let unusable:void = null;StrictNullChecks cannot be null when strictNullChecks is enabled unusable = undefined; Copy the code
Type inference
let num = 123;
Copy the code
In the above code, it does not show that num is of type number, but if you hover the cursor over num, you can see that TS automatically infer that the variable is of type number.
In general, if TS can automatically infer the type for us, we can write the type for the variable without showing it.
const one = 1;
const two = 2;
const three = one + two;
Copy the code
Ts in the above code can automatically infer the types of one, two, and three.
function getTotal(one, two) {
return one + two
}
const total = getTotal(1.2);
Copy the code
In the above code, one, two, and total are types of any. When we add the type ts to one and two, we can automatically infer the type TS for total.
Types of assertions
When we know for sure that we know the type of a variable, we can use an assertion in two ways:
-
<>
let someValue:any = "xiaoqi"; let strLength: number = (<string>someValue).length; Copy the code
-
as
let strLength:number = (someValue as string).length; Copy the code
In addition to the as primitive type, it can also be as const. There is a type widening in TS. What does TS do when we define a variable using const and let, respectively?
const a = "xiaoqi" let b = "xiaoqi" Copy the code
In this case, the type of A is “xiaoqi” and the type of B is string. Here the variable type declared by the let is broadened by the type.
type Type = "a" | "b" | "c" let x = "a"; // Use const to avoid this problem const funTest = (x:Type) = > { console.log(x) } funTest(x) // Error. Argument of type 'string' is not assignable to parameter of type 'Type' Copy the code
The above example is precisely because of the broadening of the let type. This problem can be avoided by defining variables using const.
As const can help us solve part of the problem of type widening, in addition to const.
const obj = { x: 1 } // obj is of type {x: number} const obj1 = { x: 1 as const};Obj1 is of type {x: 1}. const obj2 = { x: 1 } as const // Obj2 is of type {readonly x: 1} Copy the code
In the example above, const is not always the case, because x is of type number.
When as const is used, TypeScript infers the narrowest type for it, no broadening.
-
Not empty assertion
x! Exclude x from null and undefined.
Type the guards
Type protection is the ability to ensure that a type is within a certain range and is generally used for associative types.
-
In the keyword
interface Student { teach:boolean, study: () = >{} } interface Teacher { teach:boolean, skill: () = >{}}function person (person: Student | Teacher) { if("skill" in person) { person.skill(); }else{ person.study(); }}Copy the code
-
The typeof keyword
Typeof types can only be number, String, Boolean, or symbol.
function padLeft(value:string,padding:string|number) { if(typeof padding === "number") {return Array(padding + 1).join(' ') + value; } if(typeof padding === "string") { return padding + value } throw new Error('Expected string or number'); } Copy the code
-
The instanceof keyword
class NumberObj { constructor(public count: number){}; } function addObj(first: object|NumberObj, second:object | NumberObj) { if(first instanceof NumberObj && second instanceof NumberObj) { return first.count + second.count; } return 0; } const first = new NumberObj(6); const second = new NumberObj(8); addObj(first , second); Copy the code
Union type, cross type, type alias
-
Joint type: indicates a value can be one of several types, separated with | each type.
let value:number|string; Copy the code
-
Crossing types: To combine multiple types into a single type, using the & operator.
type PoinX = {x:number} type Point = PoinX & {y: number} let point:Point = { x:1.y:2 } Copy the code
-
Merge base type attributes of the same name
interface A { a:string, b:number, } interface B { a:number, b:number, } type AB = A & B; let ab:AB= { a:"jjj".// Error b: 9,}Copy the code
Interface A and interface B both have attributes of A, but of different types. After merging, A is of type STRING & number, which obviously does not exist. After merging, A is of type never.
-
A merge of non-primitive type attributes of the same name
interface C { c:string, } interface D { d: string, } interface A { a:C, b:number, } interface B { a:D, b:number, } type AB = A & B; let ab:AB= { a: {c:"ccc".d:"ddd"}, b: 9,}Copy the code
In the code above, although the a attribute has the same name, it is a non-basic type and can be merged.
-
-
Type the alias
Use type to give a new name to a type:
type Message = string | string[]; let say = (message: Message) = >{}Copy the code
It is also possible to rename joint types of multiple literal types:
type Dir = "left"|"right"|"up"|"down"; Copy the code
Optional chain?
Optional chains added in TypeScript 3.7? . The core is to stop the code when it encounters undefined or NULL.
letx = foo? .bar.baz();Copy the code
When foo is undefined or null, the code stops running and returns undefined.
In code we can use? Instead of &&.
/ / use &&
if(foo&&foo.bar&&foo.bar.baz) {}
/ / use? .
if(foo? .bar? .bar){}Copy the code
Notice,? Undefined and null only. There is no short circuit logic for empty strings, 0, NaN, false like &&.
Null-value merge operator??
In addition to TypeScript 3.7 introducing optional chains? . Also introduced null-value merge operators? ? . At its core, the right-hand operand is returned if the left-hand operand is undefined or null, and the left-hand operand is returned otherwise.
const foo = null ?? 'xiaoqi'
console.log(foo); // Output: "xiaoqi"
const baz = 0 ?? 42;
console.log(baz); // Output: 0
Copy the code
It can be seen and | | operators are not the same, | | operators in the left operators’, 0, NaN returns the right operand.
TypeScript class
class Person {
name = "mian"; // It defaults to public and can be used both inside and outside the class
private age = 20; // Can only be used inside a class, not inherited
protected height = 162; // Can only be used inside a class, but can be inherited and used inside a subclass
sayHello() {
return "hello"; }}Copy the code
- Inheritance: Use the extends keyword to implement inheritance.
class Jiejie extends Person{
// Override the parent method
sayHello() {
return super.sayHello() + "lala";
}
// Use the height attribute of the parent class
sayHeight() {
console.log(this.height); }}Copy the code
- Class constructor
class Person {
public name:string;
constructor(name:string) {
this.name = name;
}
/ / to simplify
// constructor(public name: string) {}
}
Copy the code
Super refers to this of the parent class. Whenever constructor is written in a subclass, super() is written even if constructor is not in the parent class.
class Teacher extends Person {
constructor(public age: number) {
super("mian"); }}Copy the code
- Use of getters, setters, static
class Jiejie {
constructor(private _age: number) {}
// Static property or method, directly called by class
static height: string = "jjj";
// Getter encapsulates the property passed in
get age() {
return this._age - 2;
}
set age(age: number) {
this._age = age; }}Copy the code
- Abstract class: A class declared using the abstract keyword and containing one or more abstract methods. Classes that inherit from abstract classes need to implement abstract methods in the abstract class.
abstract class Man {
abstract skill(): void;
}
class Waiter extends Man {
skill() {
console.log("Order"); }}class SupWaiter extends Man {
skill() {
console.log("Show me how to order."); }}Copy the code
The TypeScript interface
In object-oriented languages, interfaces are abstractions of behavior, and concrete actions need to be implemented by the class itself.
The interface in TS can not only abstract part of the behavior of the class, but also describe the attributes of the object.
-
Object Description
An interface is used to describe an object. When an object implements the interface, it must be implemented in strict accordance with the interface definition.
interface Person { name:string, age:number } const person = { name:"xiaoqi".age:20 } Copy the code
-
Optional | read-only | any attribute
interface Person { readonly name:string, / / read-onlyage? :number;/ / is optional // You can also have other attributes, with a string name and a value of any [propName:string]:any; } const person = { name:"xiaoqi".age:18.height: 163,}Copy the code
-
Description of function types
Interfaces can describe function types as well as ordinary objects with attributes.
interface AddFun { (value1:number, value2:number):boolean; } const addFun:AddFun = (val1: number,val2:number):boolean= > { if((val1 + val2) < 100 )return false; else return true; } Copy the code
-
The description of the class
A class implements an interface using implements.
interface Point { x:number, y:number, counter: (x:number,y:number) = >number, } class SomePoint implements Point { x = 1; y = 2; counter(x:number, y:number){ returnx + y; }}Copy the code
-
Inheritance of interfaces
An interface uses extends to implement interface inheritance.
interface PartialPointX { x: number; } interface Point extends PartialPointX { y:number; } const point = { x:1.y:2,}Copy the code
-
The difference between interface and type aliases
Type aliases can also describe the structure of objects, functions, and parts of classes.
type Point = { x: number, y:number } type counter = (x:number,y:number) = >boolean; const point:Point = { x: 1.y:8 } class SomePoint implements Point { x = 1; y = 4; } Copy the code
But type aliases can be used for a number of other types:
type Word = string | number; type Dir = "left" | "right" | "up" | "down"; Copy the code
Most of the time, an interface is used to describe a type, and type aliases are used if you need to use associative or tuple types.
TypeScript generic
Generics: A generic type that can be named at will (but usually uses T for generics) and declares the specific type when used.
function join<T> (first:T, second:T){
return `${first} ${second}`;
}
join<string>("xiaoq"."qi");
Copy the code
Use of arrays in generics:
function muFun<T> (params:T[]) {
return params;
}
muFun<string>(['xiao'.'qi']);
Copy the code
Definition of multiple generics:
function myFun<T.P> (first:T,second:P) {
return `${first} ${second}`;
}
myFun<string,number>("xiaoqi".18);
Copy the code
Generic definition interface:
interface KeyPair<T, U> {
key: T;
value: U;
}
let kp1: KeyPair<number, string> = { key: 123.value: "str" };
let kp2: KeyPair<string, number> = { key: "str".value: 123 };
Copy the code
Generics and inheritance in classes:
interface Girl {
name:string,
}
class SelectGirl <T extends Girl> {
constructor(private girls: T[]) {}
getGirl(index: number): string {
return this.girls[index].name; }}const girl = new SelectGirl<{name:string,age:number}>([{name:'mian'.age:18}, {name:"xiaoqi".age:19}]);
console.log(girl.getGirl(1));
Copy the code
Generic constraints:
type InitValue = {
id: number
dealer_id: number | undefined
arrive_time: string
}
/ / T type inherits the keyof InitValue the "id" | "dealer_id" | "arrive_time"
const handleChange = <T extends keyof InitValue>(curValue: InitValue[T], curIndex: number, type: T,) => {//} handleChange(8, 3, "id")Copy the code
Thus T stands for any type in the InitValue key.
typeof | keyof
-
typeof
In addition to type protection, typeof can also get the typeof a value.
const person = {name:"xiaoqi".age:20} type Sem = typeof person; const sem:Sem = { name:'zhang'.age:20 } Copy the code
-
keyof
You can get all keys of a type whose return type is a union type.
interface Person { name: string; age:number; } type K = keyof Person; // "name"|"age type K2 = keyof Person[];// number|"length" | "toString" | "toLocaleString" | "pop" | "push" | "concat" | "join" | "reverse" | "shift" | "slice" | "sort" | "splice" | "unshift" | "indexOf" | "lastIndexOf" | ... 13 more ... | "values type K3 = keyof {[x:string]:Person};// string | number class Eg2 { private name: string; public readonly age: number; protected home: string; } / / T for the age // Name and home are not public, so they cannot be retrieved by keyof type T = keyof Eg2 Copy the code
T is age and name and home are not public, so they cannot be retrieved by keyof.
Generic tools
- Partial< T>
You can make an attribute in T optional using Partial
.
export type FilterParams = {
create_start: number
create_end: number
phone: string
channel_id: number
city_id: number
}
// The properties in FilterParamsOption are optional
type FilterParamsOption = Partial<FilterParams>
/ / thattype FilterParamsOption = { create_start? : number create_end? : number phone? : string channel_id? : number city_id? : number }/ / implementation
type Partial<T> = {
[P inkeyof T]? : T[P] }// [P in keyof T] traverses all attributes on T
/ /? : Sets the property to optional
// the T[P] type is the original type
Copy the code
- Required< T>
The Required
is used to make properties in T mandatory.
export type FilterParams = {
create_start: number
create_end: number phone? : string channel_id? : number city_id? : number }// The properties in FilterParamsOption are optional
type FilterParamsOption = Partial<FilterParams>
/ / that
type FilterParamsOption = {
create_start: number
create_end: number
phone: string
channel_id: number
city_id: number
}
/ / implementation
type Required<T> = {
[P inkeyof T]-? : T[P] }Copy the code
- Pick<T, K>
Extract the list of K keys from type T to generate a new type
export type FilterParams = {
create_start: number
create_end: number
phone: string
channel_id: number
city_id: number
}
type FilterParamsOption = Pick<FilterParams, 'phone' | 'city_id'>
/ / that
type FilterParamsOption = {
phone: string;
city_id: number;
}
/ / implementation
type Pick<T, K extends keyof T> = {
[P ink ]? : T[P] }Copy the code
- Exclude<T, U>
Removes the intersection between the union type T and the union type T and returns the remainder of T.
type FilterParams = {
create_start: number
create_end: number
phone: string
channel_id: number
city_id: number
}
type FilterParams2 = {
title: string
city: number
phone: string
channel_id: number
city_id: number
}
type FilterParamsOption = Exclude<keyof FilterParams2, keyof FilterParams>
/ / that
type FilterParamsOption = "title" | "city"
/ / implementation
type Exclude<T, U> = T extends U ? never : T
Copy the code
- Extract<T, U>
Instead of Exclude, take the intersection of union type T and union type U
type FilterParams = {
create_start: number
create_end: number
phone: string
channel_id: number
city_id: number
}
type FilterParams2 = {
title: string
city: number
phone: string
channel_id: number
city_id: number
}
type FilterParamsOption = Extract<keyof FilterParams, keyof FilterParams2>
/ / that
type FilterParamsOption = "city_id" | "phone" | 'channel_id'
/ / implementation
type Extract<T, U> = T extends U ? T : never;
Copy the code
- Omit<T, K>
Corresponding to Pick<T, K>, the key value of K in T type is removed to form a new type.
export type FilterParams = {
create_start: number
create_end: number
phone: string
channel_id: number
city_id: number
}
type FilterParamsOption = Omit<FilterParams, 'phone' | 'city_id'>
/ / that
type FilterParamsOption = {
create_start: number
create_end: number
channel_id: number
}
/ / implementation
type Omit = Pick<T, Exclude<keyof T, K>>
Copy the code
- Record<K, T>
You can generate a type with a key of type K and a value of type T
type FilterParams = {
date: string[];
phone: string;
channel_id: number;
city_id: number;
}
type FilterParamsOption = Record<string, FilterParams>
/ / that
type FilterParamsOption = {
[p: string]: FilterParams
}
/ / implementation
type Record<K extends string | number | symbol, T> = { [P in K]: T; }
Copy the code
- Parameters< T >
Returns the parameter types of the T function and places each type in a tuple.
type Foo = (x: string, y: number) = > string | number
type FooType = Parameters<Foo>; // string | number
/ / that
type FooType = [x: string, y: number]
/ / implementation
type Parameters<T extends(... args: any) => any> = Textends(... args: infer P) => any ? P : never;Copy the code
- The parameter T must be a function type, so T must inherit from (… Args: any) => any or Function
- Specific implementation: Judge whether T belongs to the function type. If so, infer is used to make TS automatically infer the type of function parameter and assign it to P, and return P. Otherwise, never is returned.
- The infer keyword can only be used on the extends condition
The infer implementation retrieves the types of each element of an array:
type ArrType<T extends Array<any>> = T extends Array<infer P> ? P : never
type A = ArrType<[ 'xiaoqi'.20] >/ / that
type A = 'xiaoqi' | 20
Copy the code
- ReturnType< T>
Returns the type of the return value of T(function)
type Foo = (x: string, y: number) = > string | number
type FooType = ReturnType<Foo>; // string | number
/ / that
type FooType = string | number
type ReturnType<T extends(... args: any) => any> = Textends(... args: any) => infer P? P : never;Copy the code
- ConstructParameters< T>
Gets the parameter types of the constructor of the class, stored in a tuple.
class Person {
constructor(public name: string, age? : number) {}
}
type E1 = ConstructParameters<typeof Person>
/ / that
type E1 = [name: string, age?: number | undefined]
/ / implementation
type ConstructorParameters<T extends abstract new(... args: any) => any> = Textends abstract new(... args: infer P) => any ? P : never;Copy the code
1. T must be a class that has a constructor. 2. T must be a class that extends from an abstract class (only abstract types can be both abstract classes and ordinary classes).
class Test {}
abstract class Test2 {}
// Typeof can get a value type
// Normal assignment
const E1: typeof Test = Test
// Error: Abstract classes cannot be assigned to non-abstract types
const E2: typeof Test = Test2
// Normal assignment
const E3: typeof Test2 = Test
// Normal assignment
const E4: typeof Test2 = Test2
Copy the code
3. The difference between using classes as types and using Typeof classes as types
class Greeter {
greeting: string; // Instance properties
constructor(message: string) {
this.greeting = message;
}// constructor
greet() { // Instance method
return "Hello, " + this.greeting;
}
static PI: number = Math.PI;// Static attributes
static hi() {} // Static method
}
// Normal assignment
const e1:Greeter = new Greeter('xiaoqi')
Type "typeof Greeter" lacks the following properties of the type "Greeter" : greeting, greet
const e2:Greeter = Greeter
// Normal assignment
const e3: typeof Greeter = Greeter
Type 'Greeter' is missing the following properties in type 'typeof Greeter' :prototype, hi, PI
const e4: typeof Greeter = new Greeter('xiaoqi')
Copy the code
1. Use a class as a type, which constrains that the assigned value must be an instance of that class. This type contains all the instance members and constructors of the class. 2. Use typeof classes as types. This type contains all the static members and constructors of the class.
- Other tool types
// Uppercase the string
type Eg1 = Uppercase<'abcd'>;
/ / that
type Eg1 = 'ABCD'
// Change the string to lowercase
type Eg2 = Lowercase<'ABCs'>;
/ / that
type Eg2 = 'abcs'
// Capitalize the first letter
type Eg3 = Capitalize<'abcd'>;
/ / that
type Eg3 = 'Abcd'
// Change the first letter to lowercase
type Eg4 = Uncapitalize<'ABCD'>;
/ / that
type Eg4 = 'aBCD'
Copy the code
Special comments
-
Ts-nocheck: Add at the top of the file to make the file skip the TS check
-
Ts-check: Add to the top of the.js file to make the file ts check. Use with the JSDoc tag.
Variable declaration: use the @type tag
// @ts-check / * *@type {number} * / let a = 0; a = ""; // Failed to assign type "string" to type "number". Copy the code
2. Function type declarations: use @params and @returns tags
/ * * *@param {number} a * @param {number} b * @returns {string}* / const sum = (a, b) = > { return a + b; // Failed to assign type "number" to type "string". }; Copy the code
3, class declaration: use @public, @private, @protected, @readOnly, @static, etc
class Test { constructor() { / * *@private * / this.a = 10; / * *@readonly * / this.b = 50; }}const test = new Test(); console.log(test.a); // Attribute "A" is private and can only be accessed in class "Test". test.b += 1; // An error was reported that "b" could not be assigned because it is read-only. Copy the code
-
@ts-ignore Indicates that ts errors can be ignored. Ts will not report an error if @ts-ignore is added to the above example, but esLint will report an error if @TS-ignore is configured to disable. (@ts-expect-error does the same thing.)
const sum = (a, b) = > { // @ts-ignore return a + b; }; Copy the code
The end of the
- The basic content of the notes is taken from the blogger’s technical fat TypeScript tutorials from getting started to mastering graphic videos.
- Read more about TypeScript