preface
There’s no denying that TypeScript has become an essential skill for a front-end engineer. Rigorous type detection, on the one hand, improves the maintainability and robustness of the program, on the other hand, it also subtly improves our programming thinking, that is, logic.
So, today I’ll take a quick look at TypeScript’s advanced types by combining a real-world development scenario with some of the type definitions in the Vue 3.0 source code.
interface
Interface is used for type detection on all structured data. For example, in real development, we would define objects or arrays to describe view structures.
Define the object
Common definitions of columns in a table are:
const columns = [
{key: "username".title: "Username"},
{key: "age".title: "Age"},
{key: "gender".title: "Gender"}]Copy the code
In this case, we can define an interface named column:
interface column {
key: string.title: string
}
/ / use
const columns: column[] = [
{key: "username".title: "Username"},
{key: "age".title: "Age"},
{key: "gender".title: "Gender"}]Copy the code
Define a function
When we use axios in normal development, it can be called in many ways, such as axios.request(), axios.get(), and axios.put(). It essentially defines an interface to constrain Axios to have these methods, and it will look something like this:
export interface Axios {
request(config: AxiosRequestConfig): AxiosPromise
get(url: string, config? : AxiosRequestConfig): AxiosPromisedelete(url: string, config? : AxiosRequestConfig): AxiosPromise head(url:string, config? : AxiosRequestConfig): AxiosPromise options(url:string, config? : AxiosRequestConfig): AxiosPromise post(url:string, data? :any, config? : AxiosRequestConfig): AxiosPromise put(url:string, data? :any, config? : AxiosRequestConfig): AxiosPromise patch(url:string, data? :any, config? : AxiosRequestConfig): AxiosPromise }Copy the code
inheritance
Reusability is something we often think about when we write programs, such as component packaging, tool function extraction, function design patterns and so on. The same is true for interfaces, which can be inherited to duplicate some defined interface or class.
Here we take Vue 3.0 as an example. In the compiler stage, it divides AST Element Node into various nodes, such as ForNode, IFNode, IfBranchNode and so on. These special nodes inherit from Node:
Node inteface interface definition:
export interface Node {
type: NodeTypes
loc: SourceLocation
}
Copy the code
IFNode interface definition:
export interface IfNode extends Node {
type: NodeTypes.IF
branches: IfBranchNode[] codegenNode? : IfConditionalExpression }Copy the code
As you can see, the interface definition of Node is very clean. It describes the basic attributes needed for Node: the type of the Node, and the starting position of the LOC Node in the template. IFNode extends branches and codegenNode properties on the basis of Node, and overwrites Node’s type property to NodeTypes.IF.
Here are two properties of IFNode:
branches
That’s what it corresponds toelse
或else if
It can be one or more nodes, so it’s an array.codegenNode
Vue 3.0AST Element
It describes some properties of the node, for exampleisBlock
,patchFlag
,dynamicProps
Wait a minute, these will add upruntime
Targeted update is closely related to targeted update.
Recently, I have also been writing an article about how Vue 3.0 implements runtime + compile to gracefully implement targeted updates and static upgrades. It should be completed by the end of next week.
summary
For the introduction and use of interface, we will stop here. Of course, it also has many advanced uses such as combining generics, defining function types, and so on. Interested students can learn about this aspect of the actual combat.
Cross type and union type
Cross type
Cross type name thought meaning, have cross effect. We can merge multiple types by crossing them. For example, in Vue3, the compile phase performs a transform in addition to baseParse, so that the final AST generates executable code. Therefore, it will correspond to multiple options in the compile phase, that is, it is also a cross type:
export type CompilerOptions = ParserOptions & TransformOptions & CodegenOptions
Copy the code
The CompilerOptions alias will be used for the baseCompiler stage:
export function baseCompile(
template: string | RootNode,
options: CompilerOptions = {}
) :CodegenResult {}
Copy the code
The crossover of multiple options is because baseCompiler is only the most basic compiler, and there are more advanced compiler-DOM, compiler-SSR, and so on.
The joint type
In the same way, union types have a combined effect. That is, sometimes when you want a variable to be of type String or number, you can constrain that variable with a union type. Such as:
let numberOrString: number | string
numberOrString = 1
numberOrString = '1'
Copy the code
Also, when using union types in real development, we often encounter prompts such as:
interface student {
name: string
age: number
}
interface teacher {
name: string
age: number
class: string
}
let person: student | tearcher = {} as any
person.class = 161 "information"
// property 'person' does not exit on type `student`
Copy the code
At this point, we can use type assertions to tell TypeScript that we know what person is:
(person as teacher).class = 161 "information"
Copy the code
summary
For cross types and union types, this should be part of our normal development that we use a lot. And, from their concept, it is not difficult to understand that they are essentially the union and intersection of mathematics, but in the basic type has different performance.
Type protection and type differentiation
Type of protection
When we talked about the union type, we said that it is essentially an intersection, which also leads to the fact that we cannot directly use properties or methods outside of an intersection. Therefore, we need to use properties outside of the intersection by using type assertions in various cases to tell TypeScript what it is.
However, frequent use of type assertions undoubtedly reduces the readability of your code. TypeScript provides type protection to reduce type assertions. It is a subject-verb-object clause. For example, in the example above, we can implement type protection:
function isTeacher(person: Tearcher | Student) :person is Teacher {
return(<Tearcher>person).class ! = =undefined
}
Copy the code
The isTeacher function is then used to determine the current type, and the corresponding attribute access is performed:
if (isTeacher(person)) {
// Access teacher's unique attributes here
person.class = 162 "information"
} else {
person.name = "wjc"
}
Copy the code
The typeof and instanceof
With type protection, the question becomes: if I have multiple types in my union type, don’t I have to define multiple type-protected functions like isTeacher? Fortunately, using Typeof or Instanceof in TypeScript automatically implements type protection and differentiation.
typeof
Typeof is automatically type-protected in TypeScript for underlying types, such as:
function isNumberOrString(param: string | number) {
if (typeof param === 'string') {
return param.split(' ')}else {
return param++
}
}
Copy the code
instanceof
Unlike Typeof, which protects only base types, Instanceof protects all types. It implements type protection through constructors.
interface Person {
name: string
age: string
}
class Teacher implements Person {
name: string
age: string
constructor(name: string, age: string) {
this.name = name
this.age = age
}
teach() {
console.log("i am a teacher.")}}class Student implements Person {
name: string
age: string
constructor(name: string, age: string) {
this.name = name
this.age = age
}
study() {
console.log("i am a student.")}}const person: Student | Teacher = null as any
if (person instanceof Teacher) {
person.teach()
} else {
person.study()
}
Copy the code
summary
For typeof or instanceof but in JavaScript are old knowledge, because of the type of traditional test. We will use the Object more String. The prototype. The toString (). In TypeScript, however, the two mix well.
Type the alias
Type aliases, I think the first thing that comes to mind is alias in Webpack for aliasing paths. However, type aliases in TypeScript are similar in appearance but not in meaning. In layman’s terms, it gives a name to a type:
type age = number
const getAge = () = > age
/ / is equivalent to
interface Age {
getAge():number
}
Copy the code
Literal type
Literal types mean that we can implement enumerated types by using type aliases and union types, for example:
type method = get | GET | post | POST | PUT | put | DELETE | delete
Copy the code
Index type and mapping type
For index types and map types, here we use a common loadash function called pluck:
Implement in JavaScript:
function pluck(object, names) {
return names.map(name= > object[name])
}
Copy the code
Implement in TypeScript:
function puck<T.K extends keyof T> (object: T, names: K[]) :T[K] []{
return names.map(name= > object[name])
}
Copy the code
Here we define two generic variables T and K for puck, where K is the type inherited from all attribute names in T, so names in the parameter are constrained to be an array of attributes in T. This process is called type indexing. As for the return value T[K][] of puck function, it means that the returned value is an array, and the array value is constrained to the value of the attribute value K in T. This process is called index access.
It may be a little obscure to understand these two concepts, but it is logical to understand the process separately for each.
Write in the last
TypeScript, though, has become a must-have skill for front-end engineers. However, I believe that many partners still use Javascript more. So, there may be some confusion, how can I improve TypeScript programming? In fact, this problem is very simple, open source era, many of our problems can be solved by reading some open source project source code. I recommend reading the source code for Vue3.0 as a way to improve your TypeScript programming skills.
Writing is not easy, if you feel there is a harvest, you can handsome three combos!!
References:
- TypeScirpt Field Guide
- TypeScript official documentation
- Vuejs/vue – next (github.com/vuejs/vue-n…
)
Review previous articles
- From zero to one, take you to thoroughly understand the HMR principle in Vite (source code analysis)