The last article summarized Type annotation for TypeScript , let's talk about equally important functions and classes
function
The following declares a function type. The type alias is defined by type. void indicates that there is no return value
type fnType = () => void;
As a parameter
A function can be passed as an argument to another function
type fnType = () => void; function foo(fn: fnType) { fn(); } function bar() { console.log("bar"); } foo(bar); // bar
The difference from js code is that the passed in parameters need to define type annotations
Define function
When defining a function, you need to specify a type annotation for the input parameter. If the return value can be derived by yourself, it can also be left blank, such as the add and minus functions, but it must be written as a parameter, such as the input parameter fn in the calc function
function add(num1: number, num2: number): number { return num1 + num2; } function minus(num1: number, num2: number): number { return num1 - num2; } function calc( num1: number, num2: number, fn: (num1: number, num2: number) => void ) { console.log(fn(num1, num2)); } calc(30, 20, add); // 50 calc(30, 20, minus); // 10
Type of function parameter
The function in ts will specify the type and number of parameters. When the number is uncertain, you can use optional types, remaining parameters and default values
optional type
The optional type is equivalent to the joint type of the defined type and undefined, so there are three options for parameters: pass in the type, not pass in or undefined
function foo(x: number, y?: number) { console.log(x, y); } foo(1, 2); // 1 2 foo(3); // 3 undefined foo(4, undefined); // 4 undefined
Parameter defaults
If the parameter has a default value, it is called an optional type. However, the parameter with a default value is best placed after the required parameter
function baz(x: number = 20, y: number) { console.log(x, y); } baz(10, 20); // 10 20 baz(undefined, 20); // 20 20
Residual parameters
The remaining parameters must be passed after the parameters
function sum(num: number, ...args: number[]) { console.log(num, args); } sum(10); // 10 [] sum(10, 20); // 10 [20] sum(10, 20, 30); // 10 [20, 30]
Default derivation of this
This and ts defined in the method of object can be deduced automatically, but this in independent function cannot be deduced.
You must define the type of this in a stand-alone function
type ThisType = { name: string }; const eating = function (this: ThisType) { console.log(this.name + " eating~"); }; const person = { name: "kiki", eating, }; person.eating()
function overloading
Function overloading refers to multiple processing methods defined with the same function name and different number or types of parameters.
For example, we need to splice strings or sum numbers. Although we know that the + sign can be used for strings and numbers, in ts code with strict type detection, this writing and compilation does not pass. We need to use [type reduction] to reduce the judgment of types before processing.
By combining types, the more possible parameter combinations are, the more if statements are needed to judge, and the return value type of the function is also unknown. In this case, you can use function overload
In ts, the overloaded function of function name and parameter type is defined, and then the specific implementation is defined through the implementation function. It will be called in the overloaded function according to the data type, and then execute the code of the realization function.
function add(x: number, y: number): number; function add(x: string, y: string): string; function add(x: any, y: any) { return x + y; } console.log(add(1, 2)); console.log(add("a", "b"));
If the parameters passed are different from those defined in the overloaded function, they cannot be compiled.
class
initialization
The variables defined in the class need to be initialized. You can assign values when defining the class or operate through the constructor
class Person { name: string; age: number; constructor(name: string, age: number) { this.name = name; this.age = age; } } const person = new Person("alice", 20);
inherit
ts and js are the same. They are inherited through extensions. When using parent parameters and methods, the super keyword is used.
class Person { name: string; age: number; constructor(name: string, age: number) { this.name = name; this.age = age; } } class Student extends Person { sno: number; constructor(name: string, age: number, sno: number) { super(name, age); this.sno = sno; } } const student = new Student("alice", 20, 1);
polymorphic
Using polymorphism can write more general code. If you want to realize polymorphism, you must first have inheritance, and the parent class reference points to the child class object.
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"); } } function doAction(animals: Animal[]) { animals.forEach((animal) => { animal.action(); }); } doAction([new Dog()]); doAction([new Dog(), new Fish()]); doAction([new Dog(), new Fish(), new Animal()]);
This is equivalent to const animal1: Animal = new Dog(). It looks like an animal object, but it is actually a Dog object. The parent class reference here points to a child class object, so the last execution is the method of the Dog object
member qualifier character
There are three types of member modifiers
- Public means common and can be seen everywhere. When no member modifier is defined, it defaults to public
- Private is private and can only be accessed in the class
- protected means that the class itself and its subclasses can be accessed
public
class Person { public username: string = "alice"; getName() { return this.username; } } const person = new Person(); console.log(person.username);
private
Variables modified by private are also inaccessible on the instance object.
protected
Variables modified by protected are also inaccessible on the instance object.
readonly
readonly means that the property is read-only. After initialization, it cannot be modified in any way, whether inside the class or modifying the instance object. However, when it is an object, it is possible to modify the property of the object as long as its memory address is not changed.
Accessor
The accessor provides get/set methods for private properties, allowing us to get / modify private properties outside the class
class Person { private _name: string; constructor(newName: string) { this._name = newName; } get name() { return this._name; } set name(newName) { if (newName) this._name = newName; } } const person = new Person("alice"); console.log(person.name); person.name = "kiki"; console.log(person.name); person.name = ""; console.log(person.name);
The function of interception / judgment can be achieved by modifying private attributes through get/set attributes
Static member
Static members are defined by the static keyword. The attributes defined by static are defined in the class itself and can only be accessed by itself. They cannot be accessed inside the class and the instance object.
abstract class
When defining many general calling interfaces, we usually let the caller pass in the parent class to realize a more flexible calling method through polymorphism.
However, the parent class itself may not need to implement some methods, so the methods defined in the parent class can be defined as abstract methods.
abstract class Shape { abstract getArea(): void; } class Circle extends Shape { private radius: number; constructor(radius: number) { super(); this.radius = radius; } getArea() { return this.radius * this.radius * 3.14; } } class Rectangle extends Shape { private width: number; private height: number; constructor(width: number, height: number) { super(); this.width = width; this.height = height; } getArea() { return this.width * this.height; } } function calcArea(shape: Shape) { return shape.getArea(); } console.log(calcArea(new Circle(3))); console.log(calcArea(new Rectangle(2, 6)));
Abstract methods and methods are modified by abstract, and there are two rules when defining abstract classes:
- Abstract methods must be implemented in subclasses
- Abstract classes cannot be instantiated
Type of class
Class itself can also be used as a data type and as a type annotation.
class Person { name: string = "alice"; eating() {} } const person: Person = { name: "kiki", eating() { console.log("i am eating"); }, }; function printPerson(person: Person) { console.log(person.name); } printPerson(new Person()); printPerson(person); printPerson({ name: "macsu", eating() {} });
The type of class can be used as long as it conforms to the format of the class
Functions and classes are very important in JS and TS, which can help developers better standardize the code during development and reduce online failures~
The above is about TypeScript functions and classes. There are still many places for developers to master about js and ts. you can see other blog posts I wrote and keep updating~