Configure VScode to automatically generate TS files
- Generate ts configuration file
tsc --init
-
Activate output path
-
When the configuration is saved, it is output to the specified path
- Click Run task under the terminal
- Click typescript
- Click tsc monitor
Basic data types in TS
boolean type
let flag: boolean = true; flag = false;
number type
let num: number = 666; num = 777;
string type
let str: string = '666'; str = '777';
array type
// Mode 1 let arr: number[] = [1,2,3]; // Mode 2 let arr2: Array<number> = [6,7,8];
Tuple type
// Tuple type let arr: [number,string,boolean] = [1,'60',true];
Enumeration type
// Enumeration type enum Flag{color1 = 'blue',color2 = 'pink'}; let flag: Flag = Flag.color2; console.log(flag);
Any type of any
// Any type let num: any = 666; num = 'test'; num = true;
undefined type
// undefined type let num: undefined; console.log(num);
null type
let num: null; num = null;
void type
- Indicates that the method does not have any return type
function run(): void{ console.log('run'); }
never type
Represents a function that cannot reach the end point, such as an endless loop or throwing an exception.
function test(): never { throw new Error('error'); }
Function type of TS
basic form
function test(name: string,age: number): string{ return `${name} ---- ${age}` } test('nihao',666);
Optional parameters
In JS, the parameters defined by the function can be passed or not, but they must be passed in TS. if they are not passed, optional parameters need to be configured.
function test(name: string,age?: number): string{ return `${name} ---- ${age}` } test('nihao');
Default parameters
number in the following example is the default parameter.
function test(name: string,age: number=20): string{ return `${name} ---- ${age}` } test('nihao');
Remaining parameters
function sum(...arg: number[]): number{ return arg.reduce((pre,cur) => pre + cur,0) } sum(1,2,3,4)
function overloading
In JS, once a method with the same name is in the same scope, the following will overwrite the above, but in TS, it will be overloaded.
- Note: the following any does not mean that any type can be passed.
function test(name: string): string; function test(age: number): string; // In fact, any here is not a real any. One of the above two types must be passed. Otherwise, an error is reported function test(str: any): string{ if (typeof str === 'string') { return 'full name' + str; } else { return 'Age' + str; } } test('Reese');
Classes in TS
Definition of properties and methods in class
class Person{ name: string; constructor(n: string) { this.name = n; } run() :void { console.log(this.name); } } const p = new Person('Zhang San'); p.run();
Implementing inheritance in TS
The extension and super keywords are mainly used to implement inheritance in TS.
class Person{ name: string; constructor(name: string) { this.name = name; } run(): string { return `${this.name}I'm learning` } } class child extends Person{ constructor(name: string) { super(name); } } const c = new child('Xiao Ming'); console.log(c.run());
Modifier in class
- public: it can be called by itself, subclasses and instances
class Person{ public name: string; constructor(name: string) { this.name = name; } run(): string { return `${this.name}I'm learning` } } const p = new Person('Zhang San'); console.log(p.name);
- protected: it can be called by itself and subclasses
class Person{ protected name: string; constructor(name: string) { this.name = name; } run(): string { return `${this.name}I'm learning` } } class Child extends Person{ constructor(name: string) { super(name) } run2(): void{ console.log(this.name); } } const c = new Child('666'); console.log(c.run());
- private: it can only be accessed by itself
class Person{ private name: string; constructor(name: string) { this.name = name; } run(): string { return `${this.name}I'm learning` } } const p = new Person('Zhang San'); p.name // report errors
Note: if the class member modifier is not written, the default is public
Static properties and static methods
- Define static attributes through static keyword
class Person{ name: string; constructor(name: string){ this.name = name; } run() { console.log(this.name); } static work() { console.log('This is the static method of the class'); } } const p = new Person('Zhang San'); // p.work() / / an error is reported Person.work();
- Static methods can only call static properties, not instance properties
class Person{ name: string; static age: number = 18; constructor(name: string){ this.name = name; } run() { console.log(this.name); } static work() { console.log('This is the static method of the class'); console.log('Age is:',Person.age); } } const p = new Person('Zhang San'); Person.age; Person.work();
polymorphic
Polymorphism means that the parent class defines a method not to be implemented, but let its subclasses implement it. Each subclass has different performance.
class Animal { name: string; constructor(name: string) { this.name = name; } eat(): void { console.log('This is the parent class eat'); } } class Cat extends Animal { name: string; constructor(name: string) { super(name) this.name = name; } eat(): void { console.log('This is a polymorphism of subclasses:',this.name); } } const c = new Cat('kitten'); c.eat();
abstract class
Abstract keyword is used to define abstract classes and abstract methods. Abstract methods in abstract classes do not contain specific implementations and must be implemented in derived classes. Abstract methods can only be placed in abstract classes.
- Abstract classes cannot be instantiated concretely
abstract class Animal{ abstract eat(): void; } const a = new Animal() // Direct error reporting
- Subclasses of an abstract class must implement abstract methods in the abstract class
abstract class Animal { abstract eat(): void; } class cat extends Animal { eat(): void { console.log(666); } } const c = new cat(); c.eat()
Interface in TS
Interfaces also exist to define standards.
Attribute interface
interface fullname { firstName: string; secondName: string; } function getName (name: fullname) { console.log(`${name.firstName} + '---' + ${name.secondName}`); } const obj = { firstName: 'Small', secondName: 'bright' } getName(obj);
Optional properties of the interface
interface fullname { firstName: string; secondName?: string; } function getName (name: fullname) { console.log(`${name.firstName} + '---' + ${name.secondName}`); } const obj = { firstName: 'Small', // secondName: 'Ming' } getName(obj);
Interface of function type
interface encrypht { (key: string,value: string): string; } const md5: encrypht = function md5(key: string, value: string): string { return key + value; } console.log(md5('1','2'));
Indexable interface
This interface is mainly used to constrain arrays and objects.
- Constraints on arrays
interface useArr { [index: number]: string; } const arr: useArr = ['1','2']
- Constraints on objects
interface useObj { [index: string]: string; } const obj: useObj = { name: 'Zhang San', age: '666' }
Class type interface
The significance of class type interface is mainly to constrain classes.
interface Animal { name: string; eat(str: string): void; } class Cat implements Animal { name: string; constructor(name: string) { this.name = name; } eat(str: string): void { console.log(this.name + str); } } const cat = new Cat('little cat'); console.log(cat.eat('Corn'));
Interface expansion
Interface extension means that an interface can inherit another interface.
interface Animal { eat(): void; } interface Person extends Animal { work(): void; } class people implements Person { name: string; constructor(name: string) { this.name = name; } eat() { console.log('eat'); } work() { console.log('work'); } } const p = new people('Xiao Zhang'); p.eat() p.work()
Inheritance + implementation
interface Animal { eat(): void; } interface Person extends Animal { work(): void; } class Programer { name: string; constructor(name: string) { this.name = name; } coding(): void { console.log(this.name + 'Writing code'); } } class people extends Programer implements Person { name: string; constructor(name: string) { super(name); this.name = name; } eat() { console.log('eat'); } work() { console.log('work'); } } const p = new people('Xiao Zhang'); p.coding();
Generics in TS
Generics can support unspecified types.
Generic definition
function getData<T>(value: T): T { return value; } console.log(getData<string>('123')); console.log(getData<number>(123));
Generic type of class
class MinClass<T> { list: T[] = []; add(num: T) { this.list.push(num); } min(): T { let minNum = this.list[0]; for (let v of this.list) { if (v < minNum) { minNum = v; } } return minNum; } } const m = new MinClass<number>();
generic interface
- Writing method 1
interface configFn { <T>(value: T): T; } const fn: configFn = function<T>(value: T): T { return value; } console.log(fn<string>('666'));
- Writing method 2
interface configFn<T> { (value: T): T; } function getData<T>(value: T): T { return value; } const myGetData: configFn<string> = getData; myGetData('20')
Generic classes implement generic interfaces (for logical reuse)
Method for quickly implementing generic interface by generic class
- Define the initial structure
class MongoDb<T> implements DBI<T> { }
-
Hover the cursor and click quick fix
-
Click to implement the interface
- Classic examples
interface DBI<T> { add(info: T): boolean; update(info: T): boolean; delete(id: number): boolean; get(id: number): any[]; } /** * @description: The class that implements the generic interface must also be a generic class * @param {*} * @return {*} */ class MysqlDb<T> implements DBI<T> { add(info: T): boolean { throw new Error("Method not implemented."); } update(info: T): boolean { throw new Error("Method not implemented."); } delete(id: number): boolean { throw new Error("Method not implemented."); } get(id: number): any[] { throw new Error("Method not implemented."); } } class MongoDb<T> implements DBI<T> { add(info: T): boolean { console.log(info); return true; } update(info: T): boolean { throw new Error("Method not implemented."); } delete(id: number): boolean { throw new Error("Method not implemented."); } get(id: number): any[] { throw new Error("Method not implemented."); } } class User { username: string | undefined; password: string | undefined; } const u = new User(); u.username = 'Zhang San'; u.password = '123'; const m = new MongoDb(); m.add(u);
Namespace
- Difference between namespace and module
Namespace: an internal module, which is mainly used to organize code and avoid naming conflicts.
Module: the abbreviation of the external module of TS, focusing on code reuse. There may be multiple namespaces in a module.
namespace A { export class Animal { name: string | undefined; age: number | undefined; } } namespace B { export class Animal { name: string | undefined; age: number | undefined; } } const cat = new A.Animal() const dog = new B.Animal()
TS trimmer
What's the use of decorators?
Decorator is a special type of declaration that can be attached to class declarations, methods, properties or parameters to modify the behavior of a class. Generally speaking, decorator is a method that can be injected into classes, methods and attribute parameters to expand the functions of classes, attributes, methods and parameters.
Class decorator
Note: the implementation of the class decorator function requires the following code to be configured in the tsconfig.json file.
"experimentalDecorators": true
- Ordinary decorator (unable to pass reference)
function logClass(params: any) { // params here refers to the function below the decorator console.log(params); // Here are the properties of our dynamic expansion params.prototype.apiUrl = 'http://www.baidu.com' } // @logClass class HttpClient { constructor() { } getData() { } } const h: any = new HttpClient(); console.log(h.apiUrl);
- Decorator factory (can be referred to)
// Decorator factory function logClass(params: any) { // params: it is a parameter passed from the decorator // The following target refers to the class itself return function(target: any) { console.log('This is target: ',target); console.log('This is params: ',params); target.prototype.apiUrl = params; } } // @logClass('666') class HttpClient { constructor() { } getData() { } } const h: any = new HttpClient(); console.log(h.apiUrl); //666
Class decorator overload
function logClass(target: any) { return class extends target { apiUrl: string = 'This is a modified one url'; getData() { this.apiUrl = 'This is a modified one url---' console.log(this.apiUrl); } } } @logClass class HttpClient { apiUrl: string | undefined; constructor() { this.apiUrl = 'This is in the constructor URL' } getData() { console.log(this.apiUrl); } } const h = new HttpClient(); h.getData();
Attribute decorator
The property decorator expression will be called as a function at runtime, passing in the following two parameters
- For static members, it is the constructor of the class, and for instance members, it is the prototype object of the class.
- Name of the member.
// Attribute decorator function logProperty(params: any) { return function(target: any,attr: any) { // The target here refers to the prototype object of the class // attr here refers to the attributes of the class console.log(target); console.log(attr); target[attr] = params; } } class HttpClient { @logProperty('http://www.baidu.com') url: string | undefined; constructor() { } getData() { console.log(this.url); } } const h = new HttpClient(); h.getData()
Method decorator
In the method decorator, you can modify the method or property corresponding to the method decorator.
/** * @description: Method decorator * @param {any} params * @return {*} */ function logFun(params: any) { /** * @description: * @param {any} target: Prototype object * @param {any} methodName: Method name * @param {any} desc: Property description of the method * @return {*} */ return function(target: any,methodName: any,desc: any) { console.log(target); console.log(methodName); console.log(desc.value); const oldMethod = desc.value; desc.value = function(...args: any[]) { args = args.map(item => { return String(item) }) oldMethod.apply(this,args) } } } class HttpClient { url: string | undefined; constructor() { } @logFun('Hello') getData(...args: any[]) { console.log(args); // ['123','666'] console.log('This is getData Methods in'); } } const h = new HttpClient(); h.getData(123,'666')
Method parameter decorator
/** * @description: Method parameter decorator * @param {any} params * @return {*} */ function logParams(params: any) { /** * @description: * @param {any} target: Prototype object of class * @param {any} methodName: Method name corresponding to parameter * @param {any} paramsIndex: Index corresponding to parameter * @return {*} */ return function(target: any,methodName: any,paramsIndex: any) { console.log(params); console.log(target); console.log(methodName); console.log(paramsIndex); // Add an attribute target.apiUrl = params; } } class HttpClient { url: string | undefined; constructor() { } getData(@logParams('Hello') uuid: any) { console.log(uuid); } } const h: any = new HttpClient(); h.getData(123); console.log(h.apiUrl); //Hello
Execution sequence of trimmer
First look at the code below
function logClass1(params: any) { return function(target: any) { console.log('Class decorator 1'); } } function logClass2(params: any) { return function(target: any) { console.log('Class decorator 2'); } } function logAttribute() { return function(target: any,attr: any) { console.log('Attribute decorator'); } } function logMethod() { return function(target: any,methodName: any,desc: any) { console.log('Method decorator'); } } function logParams1() { return function (target: any,methodName: any,paramsIndex: any) { console.log('Method parameter decorator 1'); } } function logParams2() { return function (target: any,methodName: any,paramsIndex: any) { console.log('Method parameter decorator 2'); } } @logClass1('111') @logClass2('2222') class HttpClient { @logAttribute() url: string | undefined; constructor() { } @logMethod() getData() { return true } setDate(@logParams1() attr1: any,@logParams2() attr2: any) { return true; } }
Note: the execution order within class is in code order.