1. Preface ✍ ️
- As we all know,
JavaScript
Is a very flexible programming language, which on the one hand makes it the most popular programming language, on the other hand makes its code quality is uneven, high maintenance costs, runtime errors. TypeScript
Is the addition ofThe type systemtheJavaScript
.Suitable for any sizeThe project.TypeScript
的The type systemTo a great extentJavaScript
Faults.- The type system is classified according to “type check time”, which can be divided intoDynamic typeandThe static type:
- Dynamic typeType checking is performed at runtime, and type errors in this language often lead to runtime errors, which we are familiar with
JavaScript
Dynamically typed, it is an interpreted language with no compile phase. - The static typeThe type of each variable can be determined at compile time. In this language, typing errors often result in syntax errors. Due to the
TypeScript
You need to compile as before runningJavaScript
Type checking is done at compile time, soTypeScript
Belong toThe static type.
- Dynamic typeType checking is performed at runtime, and type errors in this language often lead to runtime errors, which we are familiar with
- Maybe beginners will think using
TypeScript
Additional code is required to reduce development efficiency. And what they may not know is,TypeScript
Enhanced editor (IDE) features, including code completion, interface hints, jump to definition, code refactoring, which greatly improves development efficiency.TypeScript
Type systems can bring greater maintainability and fewer bugs to large projects. - In order to improve the happiness of development, the following details will be introduced how to use it well in the project
TypeScript
.
2. Practice in the project
2.1 Make good use of type annotations
- We can get through
/ * * * /
The form of the comment is givenTypeScript
Type mark prompt:
- The editor has a better indication when hovering over a place where this type is used:
2.2 Make good use of type extension
TypeScript
There are two ways to define a type in:interface
) and type aliases (type alias
). In the following example, the types defined are the same except for the syntax:
- Both interface and type aliases can be extended:
- Interface and type aliases are not mutually exclusive, that is, interfaces can extend type aliases, and type aliases can extend interfaces:
- TypeScript: Interfaces vs Types details the differences between interface and type aliases, which are not covered here.
- Interface and type aliases when to choose:
- Used when defining a public API, such as editing a library
interface
, so that users can easily inherit the interface; - When defining component properties (
Props
) and state (State
), is recommendedtype
Because thetype
Is more restrictive; type
The type cannot be edited twice, whileinterface
It can be extended at any time.
- Used when defining a public API, such as editing a library
2.3 Make good use of declaration documents
- The declaration file must be
.d.ts
For the suffix. In general,TypeScript
Will parse all of the items in the project*.ts
File, therefore also contains the.d.ts
Closing declaration file.
- As long as
tsconfig.json
The configuration contained intyping.d.ts
Files, then everything else*.ts
The file can get the type definition in the declaration file.
2.3.1 Third-party statement documents
- When in
TypeScript
When using a third-party library in a project, we need to reference its declaration file to obtain the corresponding code completion, interface prompts and other functions. - For most third-party libraries, the community has already defined their declaration files for us to download and use. Generally recommended use
@types
Unified management of third-party library declaration files,@types
The way to use is very simple, directlynpm
或yarn
Install the corresponding declaration module. In order tolodash
For example:
2.3.2 Customizing declaration files
- When a third party library does not provide a declaration file, we need to write our own declaration file. In order to
antd-dayjs-webpack-plugin
For example, when inconfig.ts
The use ofantd-dayjs-webpack-plugin
If the editor does not find its declaration file, the following error occurs:
- When we use
yarn add @types/antd-dayjs-webpack-plugin --dev
The following error occurs while trying to resolve the problem:
- You can’t find the declaration file associated with the library (search for the declaration file you need here, if you can’t find it, you don’t have it).
- To get around the editor error, we can take another approach it provides: add an include
declare module 'antd-dayjs-webpack-plugin';
The new declaration file. We also don’t need to add files, as mentioned earliertyping.d.ts
Add the following:
The global variable
- When we need more than one
ts
Use the same in the fileTypeScript
Type when common practices will be inconstant.ts
Declare the related types in the file and place themexport
Go out to other peoplets
fileimport
Use, will undoubtedly produce a lot of tedious code. - As mentioned earlier, as long as
tsconfig.json
The configuration contains our custom declaration file*.d.ts
Declare that the type definitions in the file can be included in the project*.ts
The file is obtained. Therefore, we can combine multiplets
Files need to use the global type written in the declaration file, need to use that typets
File is not requiredimport
You can use it directly.
The namespace
- In the case of a large amount of code, to avoid variable name conflicts, functions, classes, interfaces, and so on of the same module can be placed in the namespace.
- in
ts
File usage:
- Since the official document has already introduced the relevant content of the declaration document in detail, it will not be elaborated here. Students who need it can read it by themselves.
2.4 Take advantage of new JS features supported by TypeScript
2.4.1 Optional Chaining
- Optional Chaining
? .
是ES11(ES2020)
New features,TypeScript 3.7
This feature is supported.Optional chainThis allows us to query multi-tiered objects without the need for redundant pre-validation:
- Otherwise, access directly
user.info.getAge()
Easy to hitUncaught TypeError: Cannot read property...
. - With the optional chain, the code above would look like:
- Optional chainIs an operator that checks to see if a property exists and then tries to access it.
TypeScript
Trying to accessuser.info
Before, the access will be attempted firstuser
Only whenuser
neithernull
Is notundefined
Will continue to visit ifuser
isnull
orundefined
, the expression returns directlyundefined
. - Currently, optional chains support the following syntax operations:
2.4.2 Nullish coalescing Operator (COALescing Operator)
- Null-value merge operator
??
是ES12(ES2021)
New features,TypeScript 3.7
This feature is supported. When the left-hand operand is zeronull
orundefined
, returns its right-hand operand, otherwise returns the left-hand operand.
- With the logic or operator (
||
),||
The left-hand operand is zerofalsy
Value (for example,' '
或0
) returns the right-hand operand. That is, if you use||
To set default values for some variables, you may encounter unexpected behavior:
2.5 Make good use of access qualifier modifiers
TypeScript
The class definition of theprivate
,protected
和public
These three access modifiers declare member access restrictions and are checked at compile time:public
: a public type that can be accessed inside, outside, or within a class without any modifiers.protected
: protected type, accessible within a class, within a subclass, but not outside the class;private
: private type that can only be accessed inside the current class.
- If no modifier is added, the default value is
public
Access level:
- The code above is availableTypeScript PlaygroundRun up, run in
JS
Area, we can see the escapedPerson
Class definition, with the access-qualifier removed:
- This means that the escaped code is in
JS
It can be executed correctly in the environment without limitation. But in the editor, we can seep.name
Is marked as an error, mouse over to see the specific error message. TypeScript
Extensions for stricter syntax, and LSPS and compilers to help developers inThe development environmentEarly detection and resolution of existing or alternate problems.- However, as the example above shows, the TS compiled JS library does not limit how the end user can use it. That is, if you use
TypeScript
Write a library, useprivate
或protected
To restrict member access to its users as wellTypeScript
There will be no problem when it is used, but when it is used by usersJavaScript
But not limited by expectations.
Clearly inspired by TypeScript, ECMAScript introduced a new class definition syntax in ES2015, and started thinking about member access restrictions. It proposed a Symbol and closure private member definition scheme, which was not well accepted. After another four years of thought, design, and discussion, a specification using # signs to define private members was released in ES2019. Chrome 74+ and Node 12+ already implement the specification for this private member definition.
- So even though
TypeScript
There are theprivate
Access the qualified qualifier,#privateField
In still inTypeScript
Has the meaning of existence.
2.6 Use type narrowing
TypeScript
Type narrowing is fromWide typeConverted toNarrow typeIs commonly used in scenarios where variables of union type are processed.- in
TypeScript
There are a number of ways to narrow the type of a variable:- Types of assertions
- Type the guards
- Double assertion
2.6.1 Type Assertion
- Type assertions can be explicitly told
TypeScript
The detailed type of the value. When in some scenarios, we are very sure of the type of a value, even withTypeScript
When the inferred type is inconsistent, we can use type assertion, which has the following syntax:
- in
tsx
Grammar (React
的jsx
The grammaticalts
Version) must use the former, i.eValue as type
. At the same time because<>
It is recommended that you use type assertions consistently because they are likely to conflict with generic syntaxValue as type
Syntax like this. - when
TypeScript
When we are not sure what type a variable of union type isOnly properties or methods common to all types of this union type can be accessed.
- Sometimes, however, we do need to access properties or methods specific to one of the types when we are not sure of the type, such as:
- In the example above, get
animal.swim
Error will be reported when. You can use type assertion at this point, which willanimal
Assertion intoFish
Type to resolve accessanimal.swim
The wrong question:
- Note that type assertions can only “cheat”
TypeScript
Compiler, you can’t avoid itThe runtimeError, instead of abusing type assertionsRuntime errors may result:
TypeScript
The compiler trusts our assertion and is callingswim()
When there is no compilation error, but becauseCat
There is noswim
Method, which causes an error at run time.- 🏁 : Be very careful when using type assertions, and try to avoid invoking methods after assertions or referencing deep properties to reduce unnecessary runtime errors.
2.6.2 Type guard
- There are several types of type guards:
- Typeof: Used for judgment
number
.string
.boolean
orsymbol
Four types; - Instanceof: Used to determine whether an instance belongs to a class
- In: Used to determine whether a property/method belongs to an object
- Typeof: Used for judgment
typeof
- You can use
typeof
Implement type narrowing andnever
Do a comprehensive check for the properties of the type, as shown in the following code:
- You can see at the end
else
In the branch, we narrow it down to zeronever
的foo
Assign to a display declarationnever
Variable, if everything is logically correct, then this should compile. But suppose one day your colleague changes itFoo
The type of:
- However, he forgot to modify it at the same time
controlFlowAnalysisWithNever
Method of control flow, at this timeelse
The branchfoo
The type will be narrowed down toboolean
Type, causing it to fail to assign tonever
Type, which generates a compilation error. Through the use ofnever
To avoid the occurrence of new union types without corresponding implementations, we can ensure thatcontrolFlowAnalysisWithNever
Methods are always running outFoo
To ensure code security.
instanceof
- use
instanceof
The operator Narrows the type of the variable:
in
- use
in
Do a property check:
2.6.3 Double assertion
- When we make a type assertion for a value, we need to make sure that the type inferred by the editor overlaps with the new type. Otherwise, we cannot simply make a type assertion, as shown in the following example:
- It is important to know that any type can be asserted as
any
And theany
Can be asserted to any type. - If we still want to use that type, we can use a double assertion:
TypeScript 3.0
A new one has been added tounknown
Type, it is a more secureany
A copy of. Everything can be marked as yesunknown
Type, butunkonwn
Assignment to another type must be done after type determination and condition control, and no action can be performed before type determination and condition control.- The double assertion operation in our example above is less reasonable, just to illustrate the effect of double assertion.
- 🏁 : Never use double assertion unless you absolutely have to.
- Let’s take a look at a common usage scenario: suppose we are in a
TypeScript
In the project, one was introducedJavaScript
A library written that is provided through a separate declaration fileTypeScript
Support, then there may be a situation:
method()
在.d.ts
The declared parameter type isSomeType
, but since the declaration file is not updated in time, it actually accepts another type of parameter, such asnull
.
- In this case it can be used
unknown
Type to implement incomingnull
:
- This will pass the compiler’s type check.
2.7 Make good use of constant enumeration
- Constant enumeration is used
const enum
Enumeration types defined:
- Constant enumerations differ from regular enumerations in that they are removed at compile time and cannot contain computed members (that is, constant enumerator initializers can only contain literal values and other computed enumerations).
- The result of the above example is:
- If a calculated member is included, an error is reported at compile time:
- The values of a normal enumeration are not evaluated at compile time, but are kept until the execution of the program. Let’s look at the following example:
- The result of the above example is:
- As you can see, when we don’t need an object, but the value of the object, we can use constant enumerations to avoid generating redundant code and indirect references at compile time.
2.8 Use advanced types
- In addition to
string
,number
,boolean
In addition to these basic types, we should also look at some advanced uses of type declarations.
2.8.1 Type Index (KEYOF)
keyof
Similar to theObject.keys
To get the union type of the Key in an interface:
2.8.2 Type Constraints (extends)
TypeScript
In theextends
Keywords are different from inClass
After usingextends
The inheritance function of generics, commonly used within generics, is to constrain generics:
extends
Often withkeyof
Use together, for example we have onegetValue
Method is used to retrieve the value of an object, but the object is undefinedextends
和keyof
To constrain:
- When passed the object does not
key
“, the editor will report an error.
2.8.3 Type Mapping (in)
in
The main function of keywords is to do type mapping, traversing the existing interfacekey
Or iterate over the union type. With the built-in generic interfaceReadonly
For example, its implementation is as follows:
- It makes all attributes of the interface read-only:
2.8.3 Condition Type (U? X, Y)
- The syntax of conditional types is the same as that of ternary expressions, and is often used in cases where the type is uncertain:
- That means if
T
是U
A subset of alpha is a typeX
Otherwise, it is a typeY
. With the built-in generic interfaceExtract
For example, its implementation is as follows:
TypeScript
Will use thenever
Type to represent a state that should not exist. If the type in T exists in U, return, otherwise discard.- Let’s say we have two classes that have three common attributes that can pass
Extract
Extract these three common attributes:
2.8.4 Tool Templates
TypesScript
There are a number of tool generics built in, as described earlierReadonly
,Extract
In both cases, the built-in generics are inTypeScript
The built-inlib.es5.d.ts
Is defined, so it can be used directly without any dependencies.
- Because the source code can be directly in
lib.es5.d.ts
As you can see in the file, the functions and usage of several common tool templates are described below. Exclude
The function of theExtract
On the contrary, ifT
The type ofU
If it does not exist, return, otherwise discard.
Partial
Use to set all attributes of an interface to an optional state:
Required
The effect is exactly the same asPartial
Instead, change all optional attributes in the interface to required ones:
Pick
It is mainly used to extract some attributes of the interface:
Omit
The reverse of Pick is used to remove some attributes of an interface:
3. Summarize 📝
TypeScript
Very powerful, it enhances the editor (IDE) functionality, provides code completion, interface hints, jump to definition, code refactoring, and more.TypeScript
You can andJavaScript
Coexistence, that meansJavaScript
Projects can be progressively migrated toTypeScript
.- This article introduces
TypeScript
There are several common practices in projects that I hope I haven’t touched on yetTypeScript
Or toTypeScript
If you are not familiar with the project, try to improve the maintainability of the code and the happiness of development 💪.
4. Reference documents
- TypeScript official documentation
- Sharp ES6 — Class grammar sugar
- Class element – MDN
- Understand TypeScript type narrowing