7,Typescript
Atwood's law
Jeff Atwood, one of the founders of Stack Overflow, put forward the famous Atwood law in 2007
any application that can be written in JavaScript , will eventually be written in JavaScript.
Any application that can be implemented using JavaScript will eventually be implemented using JavaScript
- web side
- Mobile terminal RN uni
- Applet side
- Desktop electron ic
- Server side node
Type detection is missing, which can easily lead to code crash and so on
7.1 type constraints
In order to make up for the defects of JavaScript type constraints and add type constraints, many companies have launched their own solutions
In 2014, Facebook launched flow to type check JavaScript
In the same year, Microsoft also launched typescript version 1.0
vue2.x uses flow for type checking
vue3.x uses TS
7.2 understanding TypeScript
TS is a js superset with types, which can be compiled into ordinary, clean and complete js code
It starts with JavaScript and ends with JavaScript
TS starts with the syntax and semantics familiar to millions of JS developers today. Use the existing JS code, including the popular JS library, and call TS code from JS code.
TS code can compile pure and concise JS code, and can run on any browser and node JS environment, any JS engine that supports ECMAScript 3 (or higher)
TS is a powerful tool for building large projects
- Type allows JS developers to use efficient development tools and common operations, such as static checking and code refactoring, when developing JS applications
- Type is optional. Type inference allows some type comments to make a big difference in the static verification of your code. Types allow you to define interfaces between software components and gain insight into the behavior of existing JS libraries
Advanced JS
- TypeScript provides the latest and evolving JavaScript features, including those from ECMAScript in 2015 and features in future proposals, such as asynchronous functions and Decorators, to help build robust components;
- These features are available when developing highly trusted applications, but will be compiled into concise ECMAScript3 (or later) JavaScript;
Many projects adopt TS
- angular
- vue3
- vscode
- Ant design UI Library
- At present, Vue3+TS react+ts is popular in the company
- Applets also support TS
7.3 TS compilation environment
As mentioned earlier, TypeScript will eventually be compiled into JavaScript to run, so we need to build a corresponding environment: we need to install TypeScript on the computer so that we can compile it into JavaScript through the TypeScript Compiler;
# Installation command npm install typescript -g # Check the version number January 21, 2022. The version number is Version 4.5.5 tsc --version
7.4 TS operating environment
Scheme I
- The first step is to compile TS to JS code through tsc
- The second step is to run JS code in the browser or Node environment
Scheme II
Through webpack, configure the local TypeScript compilation environment and start a local service, which can run directly on the browser;
Scheme III
Provide execution environment for TypeScript running through TS node library;
# Install TS node npm install ts-node -g # In addition, TS node also needs to install tslib and @ types/node packages npm install tslib @types/node -g # Now you can run TS suffix files directly through TS node ts-node math.ts
Tip: when writing ts, by default, all TS files are compiled under one scope, so they may conflict. If you want to treat each file as a separate scope, you need to add export {} at the end of each file. There are other solutions
7.5 declaration of TS variables
After declaring a type, TypeScript will carry out type detection. The declared type can be called type annotation
var/let/const identifier : data type = assignment;
Note: the string here is lowercase, which is different from string. String is the string type defined in TypeScript and string is a class defined in ECMAScript
Type derivation: in development, sometimes for convenience, we do not write the corresponding data type when declaring each variable. We prefer to use the characteristics of TypeScript to help us infer the corresponding variable type:
let message = "ddg" message = 123 // In fact, there will be errors here
This is because when a variable is assigned for the first time, the type of the variable will be inferred according to the type of the later assignment content
7.6 data types of TS and JS
[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-oaildhyf-1643279385255) (codewhy-vue3-componentization. assets/image-20220121145723489.png)]
TS is a superset of JS
7.7 TS data type number
Number type is often used in our development. TypeScript, like JavaScript, does not distinguish between integer type (int) and floating point type (double), and is unified as number type.
ES6 adds binary and octal representations, and TypeScript also supports binary, octal and hexadecimal representations:
let num: number = 123 num = 333 let num1: number = 100 // decimal system let num2: number = 0b111 // Binary, starting with 0b let num3: number = 0o456 // Octal, starting with 0o let num4: number = 0x123abc // Hexadecimal, starting with 0x
7.8 TS data type boolean
let num: boolean = true
7.9 TS data type string
let message1: string = "hello world" let message2: string = "ddg" const name = "ddg" const age = 18 const height = 1.88 let message3 = `name:${name} age:${age} height${height}` console.log(message3);
7.10 TS data type Array
// Determine the fact that although names is an array type, what type of elements are stored in the array? // In an array, in TS development, the best data type to store is fixed (string) // It's a bad habit to store different types in an array // type annotation const names: Array<string> = [] // The first method is not recommended (conflicting < div > < / div >) in react jsx and vue jsx) const names2: string[] = [] // recommend names.push('abc')
7.11 TS data type Object type
const info = { name: "Stupid dog", age: 21 } // If there is no type annotation, it will be automatically derived
7.12 null and undefined types
let n1: null = null let n2: undefined = undefined
7.13 symbol type
New knowledge of jses6. You can define the same name through symbol, because the symbol function returns different values
const t1 = Symbol("title") const t2 = Symbol("title") const info = { [t1]: "Stupid dog", [t2]: "student" } export { }
7.14 any type
In some cases, we really can't determine the type of a variable, and it may change. At this time, we can use any type
let message: any = "hello world" // When the type is set to any, it can be assigned any value /* When making some type assertions as any When you don't want to add specific data types to some JS, using any won't make mistakes. In fact, it's just like native JS */ message = 123 message = true
7.15 unknown type
unknown is a special type in TypeScript. It is used to describe variables with uncertain types.
function foo() { return "abc" } function bar() { return 123 } let flag = true let result: any // let result: unknown // Unknown types can only be assigned to any and unknown types // Any type can be assigned to any type if (flag) { result = foo() } else { result = bar() } // If the result is set to any type, there is no problem with this assignment let message: string = result let num: number = result console.log(result); console.log(message); // If result is set to unknown type, then assigning values to message and num will not work export { }
7.16 void type
viod is usually used to specify a function that has no return value, so its return value is void type
- We can assign null and undefined to void type, that is, the function can return null or undefined
function sum(num1: number, num2: number) { console.log(num1 + num2); // If there is no return value, an undefined value will be returned by default // In fact, the default return value of this function is void // We can assign null and undefined to void type, that is, the function can return null or undefined } // sum(123, 456) console.log(sum(123, 456)); export { }
7.17 never type
If a function is an endless loop or throws an exception, the function will not have a return value. Then it is not appropriate to write void type or other types as the return value type, so we can use never type
function foo(): never { // Dead cycle while (true) { // Never means that this function will never have a return value } } function bar(): never { throw new Error('Return error') } // The message here is a union type, which can be a string or a number // Prevent others from adding the type annotation of message without writing the corresponding case function handleMessage(message: string | number | boolean) { switch (typeof message) { case 'string': console.log('string Treatment method'); break case 'number': console.log('number Treatment method'); break case 'boolean': console.log('boolean Treatment method'); break default: // You can never come here, so you can assign it a value const check: never = message } } handleMessage(true) // What if you want to pass a Boolean value to the handleMessage function? // You can add a Boolean type in the type annotation of message // But in this way, you need to add another case 'boolean'
7.18 tuple type
- First, it is generally recommended to store elements of the same type in the array, and elements of different types are not recommended to be placed in the array. (can be placed in objects or tuples)
- Secondly, each element in the tuple has its own characteristic type, and the corresponding type can be determined according to the value obtained from the index value;
Basic use
// Tuple tuple, multiple element combination // Tuple type, which can determine the type of each item in the array, // If you directly write an any type to the array, it is not safe // ddg 19 180 const info: [string, number, number] = ["ddg", 18, 180] const name = info[0] console.log(name.length); const age = info[1] // console.log(age.length); export { }
Application scenario
// hooks : useState // const [counter,setCounter] = useState(10) // If there is an array in useState, it is too unsafe function useState(state: any) { // state can be an array, string, number, Boolean, and so on let currentState = state const changeState = (newState: any) => { currentState = newState } // After that, we call this function outside and deconstruct. Both values are of type any // const arr: any[] = [currentState, changeState] const arrTuple: [any, (newState: any) => void] = [currentState, changeState] // return arr return arrTuple } // At this time, counter is still of any type, while setCounter is a function type const [counter, setCounter] = useState(10) export { }
Application scenario optimization
// hooks : useState // const [counter,setCounter] = useState(10) // If there is an array in useState, it is too unsafe // If you want to optimize, you need to use generics function useState<T>(state: T) { // state can be an array, string, number, Boolean, and so on let currentState = state const changeState = (newState: T) => { currentState = newState } // After that, we call this function outside and deconstruct. Both values are of type any // const arr: any[] = [currentState, changeState] const arrTuple: [T, (newState: T) => void] = [currentState, changeState] // return arr return arrTuple } // It'll be all right at this time const [counter, setCounter] = useState(10) const [flag, setFlag] = useState(true) export { }
7.19 parameter types of functions
7.19.1 function parameters and return values
// Add type annotation to parameters // Add type annotation to the return value. When there is no return value, it is viod. Add type annotation to the return value, which is usually written after the parameter brackets of the function // In development, generally, the type of return value can not be written (automatic derivation) function sum(num1: number, num2: number): number { // The above two parameters must be passed. If you pass one, an error will be reported return num1 + num2 }
- Like the type annotation of variables, we usually do not need the return type annotation, because TypeScript infers the return type of the function according to the return value; Some third-party libraries are easy to understand and will explicitly specify the return type, but this depends on personal preferences
7.19.2 parameter types of anonymous functions
function foo(message: string) { // Usually, when defining a function, type annotations are added to the parameters } const names = ["abc", "c", "a"] names.forEach((item) => { // You can not type item // The type of item is derived from the context // When we pass one of our functions as a parameter to another function, in some cases, it will automatically deduce the type of the parameter. At this time, we can not add the type annotation })
7.19.3 function parameters are object types
// A parameter is an object function printPoint(point: { x: number, y: number }) { // Point: {X: number, Y: number} each key in this object can be separated by commas or semicolons console.log(point.x); console.log(point.y); } printPoint({ x: 20, y: 30 }) // Parameter is a string function printString(message: string) { }
7.19.4 optional parameters of function
// A parameter is an object // If the user needs to transmit x,y,z, Z, is optional, z?:number, just add a question mark after Z function printPoint(point: { x: number, y: number, z?: number }) { // Point: {X: number, Y: number} each key in this object can be separated by commas or semicolons console.log(point.x); console.log(point.y); } printPoint({ x: 20, y: 30 }) printPoint({ x: 20, y: 30, z: 1111 }) // Parameter is a string function printString(message: string) { } export { }
7.19.5 joint type
TypeScript's type system allows us to use multiple operators to build new types from existing types.
- Union Type
- A union type is a type that consists of two or more other types
- The representation can be any of these types
- Each type in a union type is called a union's members
// number | string union type function printID(id: number | string) { // Be especially careful when using union type values // narrow: zoom out if (typeof id === 'string') { // ts helps determine that the id must be of type string console.log(id.toUpperCase()); } else { console.log(id); } } printID(123) printID('abc') export { }
7.19.6 type alias
// Type defines the type alias type IDType = string | number | boolean type PointType = { x: number, y: number, z: number } function printId(id: IDType) { } function Point(id: PointType) { } export { }
7.20 type assertion as
Sometimes TypeScript cannot obtain specific type information, so we need to use Type Assertions
For example, we use document Getelementbyid, TypeScript only knows that this function will return HTMLElement, but does not know it
Specific types
TypeScript only allows type assertions to be converted to more specific or less specific type versions. This rule prevents impossible casts
Not very specific. It means any or unknown
// <img id="ddg"/> const el = document.getElementById("ddg") as HTMLImageElement el.src = "url address" // An error will be reported: the attribute "src" does not exist on the type "HTMLElement". // document.getElementById("ddg") as HTMLImageElement so that no error will be reported when modifying // Convert a universal type into a specific type class Person { } class Student extends Person { studying() { } } function sayHello(p: Person) { // p.studying() / / you can't access it directly (p as Student).studying() } const stu = new Student() sayHello(stu) // 3. This is not recommended const message = "hello world" // const num: number = message // const num: number = (message as any) as number // const num: number = (message as unknown) as number export { }
7.21 non null type assertion
// message ? => undefined | string function printMessage(message?: string) { // Others may or may not pass it on // If it is not transmitted, an error will be reported // console.log(message.length); // However, we can use non null type assertions when we are sure that the passed in parameters have values // Non null assertions use, Indicates that it can be determined that an identifier has a value and skip ts's detection of it at the compilation stage // ! It means that message must have a value console.log(message!.length); } printMessage("hello world") // printMessage()
Although it evades the inspection, the code is not rigorous enough
7.22 use of optional chains es11(es2020)
In fact, the optional chain is not a unique feature of TypeScript. It is an added feature in ES11 (ES2020)
- Optional chains use the optional chain operator
- Its function is that when the attribute of the object does not exist, it will be short circuited and return to undefined directly. If it exists, it will continue to execute
type Person = { name: string, friend?: { name: string, age?: number, } } const info: Person = { name: "Stupid dog", // friend: { // name: "kobe" // } } // In another file, console.log(info.name); //console. log(info.friend); // info. Friends may or may not get it. Friend is optional console.log(info.friend?.name); // The friend of info may or may not have a value. If there is no friend, the following code will not be executed, and the whole expression returns undefined
7.23 ?? !!
!!
- Converts a different type to a boolean type
- Similar to Boolean (variable)
??
- It is an added feature of ES11
- Null merge operator (?) Is a logical operator. When the left side of the operator is null or undefined, it returns its right operand; otherwise, it returns the left operand
const message = "hello wolrd" // const flag = Boolean(message) // console.log(flag); // !! It is the feature of js itself const flag = !!message console.log(flag);
let message: string | null = null // If message is null, give him a default value const content = message ?? "How do you do" console.log(content); export { }
7.24 literal type
Literal quantity is more common than union type,
// If it is a let definition, its type is string let message = "hello world" // If const is defined, its type is const message2: "hello world" // In other words, hello world is a type called literal type const message2 = "hello world" let num: 123 = 123 // num = 321 it is impossible to modify the value of literal class. The type must be equal to the value // The meaning of literal type is that it must be combined with union type let align: 'left' | 'right' | 'center' = 'left' align = "right" // This assignment is no problem. The assigned value must be one of the types export { }
7.25 literal reasoning
// If you don't write a type annotation, he will deduce it automatically const info = { name: "ddg", age: 20 } info.name = "kobe" // example type Method = 'GET' | 'POST' function request(url: string, method: Method) { } // Scheme 1: write dead type annotation Proposal 1 // type Request = { // url: string, // method: Method // } // const options: Request = { // url: "http://www.daidaigou.top", // method: "POST" // } // Option 3 const options = { url: "http://www.daidaigou.top", method: "POST" } as const // When passing, the second parameter will report an error because options The type of Method attribute will be automatically deduced as string, and the second parameter of the function is Method // request(options.url, options.method) // request(options.url, options.method) // Scheme 2 uses type assertion request(options.url, options.method as Method)
7.26 type reduction
- Type Narrowing in English is Type Narrowing
- We can change the execution path of TypeScript through a judgment statement similar to typeof padding = = = "number"
- In a given execution path, we can reduce types smaller than those declared. This process is called reduction
- The typeof padding === "number" we wrote can be called type guards
Common types of protection are as follows
- typeof
- Equal reduction (e.g. = =,! = =)
- instanceof
- in
- Wait
// 1. Type reduction of typeof function printID(id: number | string) { // id is a union type and cannot be processed casually // The whole process of the statement is called type reduction if (typeof id === 'string') { // The id obtained here must be a string type console.log(id.toUpperCase()); } else { console.log(id); } } // 2. Reduction of the type of equality (= = =! = =! = switch) function printDireaction(direction: 'left' | 'right' | 'top' | 'bottom') { // if (direction === "left") { // }else if () { // } // switch(direction){ // case 'left': wait // } } // 3.instanceof function printTime(time: string | Date) { if (time instanceof Date) { // If it is date type } else { console.log('xxx'); } } class Student { studying() { } } class Teacher { teaching() { } } function work(p: Student | Teacher) { if (p instanceof Student) { p.studying() } else { p.teaching() } } const stu = new Student() work(stu) // work passes an instance of Student or Teacher // 4. in type Fish = { swimming: () => void } type Dog = { running: () => void } function walk(animal: Fish | Dog) { if ('swimming' in animal) { // Is to judge the attribute. The Fish Dog here is not a class, but a literal quantity animal.swimming() } else { animal.running() } } const fish: Fish = { swimming() { console.log("swimming"); } } walk(fish)
7.27 function type
7.27.1 function type
// 1. How to write types in parameters when functions are used as parameters function foo() { } function bar(fn: () => void) { fn() } bar(foo) // 2. When defining constants, write the type of function const add: (num1: number, num2: number) => number = (num1: number, num2: number) => { return num1 + num2 }
7.27.2 optional types of parameters
// y -> undefined | number function foo(x: number, y?: number) { } // The first parameter must be selected! foo(20, 30) foo(40)
7.27.3 default values of parameters
// Write the required parameters first - parameters with default values - optional parameters function foo(x: number = 20, y: number = 100) { console.log(x, y); } foo(undefined, 40)
7.27.4 residual parameters of function
function sum(...nums: number[]) { console.log(nums); } sum(10, 20, 30, 40, 50)
7.27.5 this
// this can be derived, info object (derived from TS) const info = { name: "Stupid dog", eating() { console.log(this.name + " eating"); } } info.eating()
// this cannot be used indiscriminately in TS // The independent function can't deduce this // Solution: pass a parameter and put it first function eating(this: { name: string }) { console.log(this.name + " eating"); } const info = { name: "Stupid dog", eating: eating, } // Implicit binding info.eating() // Display binding // If this is passed, eating() cannot be written directly eating.call({ name: "2222" }) export { }
7.27.6 overloading of functions
In TypeScript, if we write an add function to add string and number types, how should we write it?
- In TypeScript, we can write different overload signatures to indicate that functions can be called in different ways
- It is generally to write two or more overloaded signatures, and then write a general function and implementation
// Function overloading: several functions with the same function name but different parameters are function overloading // TS function overloading, top-down matching, and the function body is written at the end // Written in other languages // function add(num1: number, num2: number) { } // function add(num1: number, num2: number, num3: number) { } // TS function overload writing method function add(num1: number, num2: number): number; // No function body function add(num1: string, num2: string,): string; // Implementation function, this function is the implementation function function add(num1: any, num2: any): any { // Function body if (typeof num1 === 'string' && typeof num2 === 'string') { return num1.length + num2.length } return num1 + num2 } console.log(add(20, 30)); console.log(add('123', '456')); // In function overloading, the implementation function cannot be called directly. It must be matched from top to bottom // add({name: "stupid dog"}, {age:29})
// If you can simply implement it through union types, use union types // Implementation method 1: joint type implementation // function getLength(args: string | any[]) { // return args.length // } // console.log(getLength("abc")); // console.log(getLength([12, 23, 11, 23])); // Implementation mode 2: function overload implementation function getLength(args: string): number; function getLength(args: any[]): number; function getLength(args: any): number { return args.length } console.log(getLength("abc")); console.log(getLength([12, 23, 11, 23]));
Category 7.28
- In the early JavaScript development (ES5), we need to realize class and inheritance through function and prototype chain. Starting from ES6, the class keyword is introduced to make it easier to define and use classes
- As a superset of JavaScript, TypeScript also supports the use of class keyword, and can also carry out static type detection on class properties and methods
- In fact, during the development of JavaScript, we are more used to functional programming
- For example, in the development of React, more function components are used and the development mode combined with Hook
- For example, in the development of Vue3, the use of Composition API is also more advocated
- However, when encapsulating some businesses, classes have more powerful encapsulation, so we also need to master them
- For class definition, we usually use the class keyword:
- In the object-oriented world, everything can be described by class structure;
- Class contains unique attributes and methods;
7.28.1 definition of class
// The properties of a class must be initialized, either directly at the time of definition or with a constructor class Person { // Properties and methods // You can directly assign and initialize after defining the attribute // name: string = "" // age: number = 0 name: string age: number // constructor can also be used for initialization constructor(name: string, age: number) { this.name = name this.age = age } eating() { console.log(this.name + " eating"); } } const p = new Person("ddg", 21) export { }
7.28.2 inheritance of classes
class Person { name: string = "" age: number = 0 eating() { console.log("eating"); } } class Student extends Person { sno: number = 0 studying() { console.log("studying"); } } class Teacher extends Person { titlle: string = "" teaching() { console.log("Teachering"); } } const stu = new Student() console.log(stu); stu.eating()
class Person { name: string age: number constructor(name: string, age: number) { this.name = name this.age = age } eating() { console.log("Person eating"); } } class Student extends Person { sno: number constructor(name: string, age: number, sno: number) { super(name, age) // Call the constructor of the parent class this.sno = sno } // If the subclass is not satisfied with the method of the parent class, it can override it eating() { console.log("Student eating"); // What if you have to call the method of the parent class in the subclass? super.eating() } studying() { console.log("studying"); } } const stu = new Student("ddg", 21, 201813212) console.log(stu); stu.eating() export { }
7.28.3 member modifier of class
In TypeScript, class properties and methods support three modifiers: public, private and protected
- Public modifies attributes or methods that are visible and public anywhere. The default attribute is public;
- Private modifies attributes or methods that are only visible and private in the same class and the current class;
- Protected modifies attributes or methods that are visible and protected only in the class itself and its subclasses;
// protected: it can be accessed inside the class and in subclasses, class Person { protected name: string = "" getName() { return this.name } } const p = new Person() console.log(p.name); // This is not accessible, and an error will be reported export { }
7.28.4 readonly read only attribute
class Person { // Read only attribute, which can be assigned in the constructor. After assignment, it cannot be modified // The property itself cannot be modified, but if it is an object type, the properties in the object can be modified. Similar to const readonly name: string age?: number readonly friend?: Person constructor(name: string, friend?: Person) { this.name = name this.friend = friend } } const p = new Person("ddg", new Person("boke")) // At this time, the name can only be accessed and cannot be modified // p.name = "123" console.log(p.name); console.log(p.friend); // Friends cannot be modified directly // p.friend = new Person("hames") if (p.friend) { p.friend.age = 30 }
7.28.5 getter and setter
class Person { private _name: string constructor(name: string) { this._name = name } // Accessor setter / getter // Suggestion: private attribute, beginning with underscore set name(newName) { this._name = newName } get name() { return this._name } } const p = new Person("Stupid dog") // console.log(p.name); p.name = "Stupid dog------" console.log(p.name);
7.28.6 static members
class Student { static time: string = "20:00" static attdendClass() { console.log('Go to school'); } } // It can be accessed directly through classes console.log(Student.time); console.log(Student.attdendClass()); export { }
7.28.7 abstract classes
- Abstract functions can have no function body. Abstract functions must be in abstract classes
- Abstract classes cannot be instantiated, that is, they cannot be created through new
- Methods of abstract classes must be implemented in subclasses
function makeArea(shape: Shape) { return shape.getArea() } // Parent class abstract class Shape { // Abstract functions can have no function body. Abstract functions must be in abstract classes // Abstract classes cannot be instantiated // Methods of abstract classes must be implemented in subclasses abstract getArea(): number } class Rectangle extends Shape { private width: number private height: number constructor(width: number, height: number) { // This is a subclass. You must call super() of the parent class super() this.width = width this.height = height } getArea() { return this.width * this.height } } class Circle extends Shape { private r: number constructor(r: number) { super() this.r = r } getArea() { return this.r * this.r * 3.14 } } const rectangle = new Rectangle(20, 30) const circle = new Circle(10) console.log(makeArea(rectangle)) console.log(makeArea(circle)) // makeArea(new Shape()) // makeArea(123) // makeArea("123")
7.28.8 type of class
class Person { name: string = "123" eating() { } } const p = new Person() // Class itself can also be used as a type const p1: Person = { name: "Stupid dog", eating() { } } function printPerson(p: Person) { console.log(p.name); } printPerson(new Person()) printPerson({ name: "hit", eating: function () { } })
7.29 interface
7.29.1 interface definition object type
// The first is to declare an object type through a type alias // type InfoType = { name:string,age:number} // The second is through the interface // interface type name // The type name after the interface is usually preceded by an uppercase I interface InfoType { readonly name: string, age: number } const info: InfoType = { name: "ddg", age: 12 } // Because the read-only attribute is added, an error will be reported // info.name = "@22"
7.29.2 index type
// interface to define the index type interface IndexLanguage { // index is a formal parameter // [index: number]: string | boolean [index: number]: string } const frontLanguage: IndexLanguage = { 0: "html", 1: "css", 2: "js", 3: "vuejs", // 4: true } interface ILanguageYear { // name is a parameter [name: string]: number } const languageYear = { "c": 1972, "java": 1995, "js": 1996, "ts": 2014 }
7.29.3 function type
interface CalcFn { // Interface definition function type (n1: number, n2: number): number } // It is recommended to use type to define function type // type CalcFn = (n1: number, n2: number) => number function calc(num1: number, num2: number, calcFn: CalcFn ) { return calcFn(num1, num2) } const add: CalcFn = (num1, num2) => { return num1 + num2 } calc(20, 30, add)
7.29.4 interface inheritance
There are two ways to combine multiple interfaces
- Interface inheritance
- Cross type
interface ISwim { swmming: () => void } interface IFly { flying: () => void } interface IAaction extends ISwim, IFly { // Interface inheritance, supporting multiple inheritance } const action: IAaction = { swmming() { }, flying() { } }
7.29.5 crossing type
// A way to combine types: Union type type DdgType = number | string type Direaction = "left" | "right" | "center" // Another way to combine types: cross type // The & here means that it conforms to both the previous type and the following type type oneType = number & string // &: what does it mean interface ISwim { swmming: () => void } interface IFly { flying: () => void } type mytype1 = ISwim | IFly type mytype2 = ISwim & IFly const obj: mytype1 = { // You can choose between swmming and flying swmming() {} } const obj2: mytype2 = { // You can write both swmming() {}, flying() { } } export { }
7.29.6 implementation of interface
interface IEat { eating: () => void } interface ISwim { swmming: () => void } // Class implementation interface class Animal { } // Class inheritance: only single inheritance can be implemented // Implementation: implement interfaces, and multiple interfaces can be implemented class Fish extends Animal implements ISwim, IEat { eating() { console.log('fish eating'); } swmming() { console.log('fish swmming'); } } class Person implements ISwim { swmming() { console.log('person swimming'); } } // Write some common APIs: interface oriented programming function swimAction(swimable: ISwim) { swimable.swmming() } // 1. All objects corresponding to classes that implement interfaces can be passed in swimAction(new Fish()) swimAction(new Person())
7.29.7 difference between interface and type
- We will find that both interface and type can be used to define object types. Which one should we choose when defining object types in development?
- If you are defining non object types (functions, union types), it is generally recommended to use types, such as Direction, Alignment, and some functions;
- If you define object types, they are different
- Interface can repeatedly define attributes and methods for an interface;
- type defines an alias, which cannot be repeated;
[the external chain picture transfer fails, and the source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-fir6veya-1643279385256) (codewhy-vue3-componentization. assets/image-20220127120910909.png)]
interface IFoo { name: string } interface IFoo { age: number } // TS allows you to define two interfaces with the same name. TS will merge these two interfaces internally const foo: IFoo = { age: 18, name: "sting" } // type does not allow two aliases with the same name, that is, aliases cannot be repeated // type IBar = { // name: string // } // type IBar = { // age: number // }
7.29.8 literal assignment
interface IPerson { name: string, age: number, height: number } const info = { name: "ddg", age: 19, height: 2.0, address: "Beijing" } // During type checking, info is assigned to IPerson, and the two are compared. First erase the address, and then compare how they are the same. If they are different, assignment is allowed // freshness erase const p: IPerson = info // Its meaning function p2(obj: IPerson) { } // P2 ({Name: "DDH", age: 20, height: 1.8, address: "Beijing"}) / / an error will be reported because an additional address attribute is passed const obj2 = { name: "ddh", age: 20, height: 1.8, address: "Beijing" } p2(obj2)
7.29.9 enumeration types
- Enumeration is actually to enumerate a group of possible values one by one and define them in a type. This type is the enumeration type
- Enumeration allows developers to define a set of named constants, which can be numeric or string types
// type Direction = "left" | "Right" | "Top" | "Bottom" enum Direction { LEFT, RIGHT, TOP, BOTTOM } function turnDirection(direction: Direction) { switch (direction) { case Direction.LEFT: console.log("Change the direction of the character to the left") break; case Direction.RIGHT: console.log("Change the direction of the character to the right") break; case Direction.TOP: console.log("Change the direction of the character up") break; case Direction.BOTTOM: console.log("Change the direction of the character down") break; default: // Only by exhausting the above types, there will be no error reported here const foo: never = direction; break; } } turnDirection(Direction.LEFT) turnDirection(Direction.RIGHT) turnDirection(Direction.TOP) turnDirection(Direction.BOTTOM)
enum Direction { // The default value of these four properties is 0, and you can also modify the value // If only the first one is modified and the first one is changed to 100, the next three will increase // If only the fourth one is modified, the first one is 0, the second one is 1, and the third one is 2 // Its value can also be a string, usually a string or a number LEFT = 100, RIGHT = 200, TOP = 300, BOTTOM = 400 } function turnDirection(direction: Direction) { // console.log(direction); Enumeration types actually have values switch (direction) { case Direction.LEFT: console.log("Change the direction of the character to the left") break; case Direction.RIGHT: console.log("Change the direction of the character to the right") break; case Direction.TOP: console.log("Change the direction of the character up") break; case Direction.BOTTOM: console.log("Change the direction of the character down") break; default: // Only by exhausting the above types, there will be no error reported here const foo: never = direction; break; } } turnDirection(Direction.LEFT) turnDirection(Direction.RIGHT) turnDirection(Direction.TOP) turnDirection(Direction.BOTTOM) export { }
7.30 generics
- The main purpose of software engineering is to build not only clear and consistent API s, but also make your code highly reusable
- For example, we can encapsulate some API s through functions, and let functions help us complete different operations by passing in different function parameters
- But can the type of parameter be parameterized
- What is type parameterization?
- Let's put forward a requirement: encapsulate a function, pass in a parameter, and return this parameter;
- If we are thinking in TypeScript, we should consider that the type of this parameter and the return value should be consistent:
7.30.1 basic use
// Parameterization of types // When defining this function, I do not determine the type of these parameters // Instead, let the caller tell me in the form of parameters what type the function parameters here should be function sum<Type>(num: Type): Type { return num } // 1. Call method 1: clear incoming type sum<number>(20) sum<{ name: string }>({ name: "why" }) sum<any[]>(["abc"]) // 2. Call method 2: push type to sum(50) sum("abc")
7.30.2 basic supplement of generics
-
T: Abbreviation for Type
-
K. V: abbreviation of key and value, key value pair
-
E: Abbreviation for Element
-
O: Abbreviation for Object
function foo<T, E>(arg1: T, arg2: E) { } foo<number, string>(10, 'How do you do~~~')
7.30.3 generic interfaces
interface IPerson<T1 = string, T2 = number> { name: T1, age: T2 } // The corresponding type must be written here and will not be deduced automatically const p: IPerson<string, number> = { name: "ddg", age: 20 } const p2: IPerson = { name: "ddg1", age: 30 }
7.30.4 generic classes
class Point<T> { x: T y: T z: T constructor(x: T, y: T, z: T) { this.x = x this.y = y this.z = y } } const p1 = new Point("1.33.2", "2.22.3", "4.22.1") const p2 = new Point<string>("1.33.2", "2.22.3", "4.22.1") const p3: Point<string> = new Point("1.33.2", "2.22.3", "4.22.1") const names1: string[] = ["abc", "cba", "nba"] const names2: Array<string> = ["abc", "cba", "nba"] // Not recommended (react JSX < >) export { }
7.30.5 type constraints for generics
For example, both string and array have length, or some objects also have length attribute
So as long as the attribute with length can be used as our parameter type, how should we operate?
interface ILength { length: number // Indicates: if it is an object type, it must have the length attribute } // extends inherits a type, // Make a constraint on this generic type function getLength<T extends ILength>(arg: T) { return arg.length // You must have the attribute length, so that you will not report an error after passing it } // Getlength (123) / / type number has no length attribute getLength("abc") // Because the string itself has the length attribute getLength(["abc", "cba"]) getLength({ length: 100 }) console.log(getLength({ length: 100 })); console.log(getLength(["abc", "cba"]));
7.31 modular development
TypeScript supports two ways to control our scope
- Modularization: each file can be an independent module, which supports ES Module and CommonJS
- Namespace: declare a namespace through namespace
Namespace namespace
In the early days of TypeScript, namespaces were called internal modules. The main purpose is to divide the scope within a module to prevent some naming conflicts
export namespace time { // In addition to the time curly braces, if you want to get it, you must export it export function format(time: string) { return "2022-22-02" } export function foo() { } export let name: string = "Stupid dog" } export namespace price { export function format(price: number) { return "99.9999" } } time.format // time.foo
// main.ts import { time, price } from './utils/format'; console.log(time.format('xxx'));
7.32 type search
In the past, almost all types in our typescript were written by ourselves, but we can also use some other types:
const imgId = document.getElementById('image') as HTMLImageElement
Will you wonder where our HTMLImageElement type comes from? Why can a document even have a getElementById method?
In fact, this involves typescript's type management and search rules
- The typescript files we wrote before are ts files, which will eventually be output js file is also where we usually write code
- There is another kind of file d.ts file, which is used for type declaration. It is only used for type detection to tell typescript what types we have
So where does typescript find our type declaration?
- Built in type declaration
- Externally defined type declaration (usually the type declaration file of the third-party library, such as axios)
- Define your own type declaration
7.33 built in type declaration
- The built-in type declaration is a declaration file that comes with typescript and helps us build some standardized API s of JavaScript runtime;
- Including built-in types such as Math and Date, as well as DOM API s such as Window and Document
Built in type declarations are usually included in the environment where we install typescript Official website address
7.34 external definition type declaration
For example, axios is an externally defined type declaration
node_ modules => axios =>index. d.ts . Axios has helped us
- External type declarations are usually required when we use some libraries (such as third-party libraries).
- These libraries usually have two types of declarations:
- Method 1: make type declaration in your own library (write. d.ts file), such as axios
- Method 2: store the type declaration file through a public library of the community, DefinitelyTyped
- GitHub address of the Library: https://github.com/DefinitelyTyped/DefinitelyTyped/
- The library looks for the address where the installation method is declared: https://www.typescriptlang.org/dt/search?search=
- For example: npm i react, NPM I @ types / react -- save dev
7.35 self defined type declaration
Generally, a new one is created under src d. File at the end of TS
// declare is declared declare module 'lodash' { export function join(arr: any[]): void { } }
// main.ts, provided that NPM I @ types / lodash -- save dev has not been executed import lodash from 'lodash' console.log(lodash.join(["1"]));
Declare variable
In the root file index.html In the file <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js "></script> <script> let whyName = "coderwhy" let whyAge = 18 let whyHeight = 1.88 function whyFoo() { console.log("whyFoo") } function Person(name, age) { this.name = name this.age = age } </script>
// main.ts import { add, sub } from './utils/math'; import { time, price } from './utils/format'; // import lodash from 'lodash' // console.log(lodash.join(["1"])); // In TS, the introduction of a picture will also report an error import nhltImg from './img/nhlt.jpg' console.log(add(20, 30)); console.log(sub(20, 30)); console.log(time.format('xxx')); console.log(whyName); console.log(whyAge); console.log(whyHeight); console.log(whyFoo()); const p = new Person("ddg", 20) console.log(p); $.ajax({})
// ddg.d.ts // The. d.ts file does not need to be written and implemented, but only defined // declare is declared // This is the declared module declare module 'lodash' { export function join(arr: any[]): void { } } // You can also declare variables / functions / classes declare let whyName: string declare let whyAge: number declare let whyHeight: number declare function whyFoo(): void declare class Person { name: string age: number constructor(name: string, age: number) } // Declaration document declare module '*.jpg' declare module '*.jpeg' declare module '*.png' declare module '*.svg' declare module '*.gif' // Declaring Namespace // For example, in index The cdn address of jq is introduced into HTML declare namespace $ { export function ajax(settings: any): any }