Why does it happen?any
- I don’t know exactly how to define a type,
TS
Error, useany
If you can, use itany
了 - I feel that defining a type is a waste of time, the project manager is pushing me, the schedule is tight,
any
It is more convenient
Frequent use ofany
The disadvantages of
- Not conducive to good coding habits
- It is not conducive to subsequent maintenance of the project
- A lot of things could have been avoided
bug
Use only when necessaryany
The benefits of
- Good code tips
- Powerful static type checking
- Readability and maintainability
So, we say no to AnyScript!
TS tends to appearany
Scene combing
Add attributes to the Window global object
You see this all the time
; (<any>window).obj = {}(
/ / or
window as any
).obj = {}
Copy the code
Doing so requires an assertion both at use and at assignment, which is cumbersome and does not prompt the code to use it
The right thing to do is
- In the project global
xxx.d.ts
The following code is configured in the file
interface Window {
obj: {}}Copy the code
- The need to give
window
Create a new directory below the assigned file directory@types
Folder and create a new folder in itindex.d.ts
File, add the following code
interface Window {
obj: {}}Copy the code
Method 2 also adds the obj declaration to the global window. If the new attributes are used over a large span, it is recommended that they be placed in the project’s index.d.ts, which is easier to maintain. But method 1 can tell at a glance what attribute was added to the window in the project
Proper use of optional chain, non-null assertions
Misinterpreting typescript optional arguments and using assertions leads to pitfalls
const a: {
b: stringc? : {d: string}} = {b: "123",}console.log((<any>a).c.d) // Error, such access will report an error, should use optional chain
console.log(a.c! .d)// Error, ts will not throw the error, but the actual access will also report an error
Copy the code
! A non-null assertion is similar to as in that it is used to assert that the value of an attribute is not null or undefined. It does not affect the final code production, but only type verification during code compilation
? . Optional chain operators affect compiled code artifacts, such as:
This ts code
const a = {
c: undefined,}constb = a? .c? .dCopy the code
This will be compiled into the following JS code
"use strict"
var _a$c
const a = {
c: undefined,}const b =
a === null || a === void 0
? void 0
: (_a$c = a.c) === null || _a$c === void 0
? void 0
: _a$c.d
Copy the code
Correlating object property types
There are multiple properties in an object that are union types, where a is associated with b, where a is 1, b is string, a is 2, b is number and that’s how we usually define it
const obj: {
a: 1 | 2
b: string | number
} = {
a: 1.b: "1.2"
}
Copy the code
When used, this results in a situation where an assertion is needed to limit the scope of B again, as shown in the code snippet below
if (obj.a === 1) {
const [left, right] = (obj.b as string).split(".")}// If you are lazy, this may be the case again
if (obj.a === 1) {
const [left, right] = (obj.b as any).split(".")}Copy the code
Is there any way we can not do it again? There are
const obj: {
a: 1
b: string
} | {
a: 2
b: number
} = {
a: 1.b: "1.2"
}
// You'll notice that once you've done this, you don't need to assert again to limit the scope of obj.b
if (obj.a === 1) {
const [left, right] = obj.b.split(".") // The check is successful
}
Copy the code
If we apply this method to function (which can also be implemented with overloading) or component argument passing, it is interesting that it can also limit the scope of argument passing. Function component implementation:
Incorrect parameter transmission. The type of A and B do not match. The verification fails
Correct parameter transmission, verification can pass
Note: You cannot deconstruct the props as this will cause the relationship between the two to be lost
const { a, b } = props // Error, the type relationship between a and B is missing
Copy the code
The use of union types needs to be treated dialectically, and it can be a bit bloated to define them in this way all the time
Smart type protection to avoid assertions
In typescript, typeof, instanceof, and in keywords are commonly used for type protection. These keywords are easy to master. There is another keyword that typescript provides: IS (type predicate). It’s another type of protection.
Type predicates allow us to do complex type checking logic in the form of functions. The declaration of a function that uses type predicates is usually of the following form:
type X = xxxx // A certain type
function check(params) :params is X
Copy the code
Params is of type X if check returns true, but not necessarily X otherwise
Imagine a scenario where a project may run in a wechat web page or other WebView
In the wechat webpage, wechat client injects various native methods into the window object, and the way to use it is window.wx.xxxx().
In other webview, we assume that there are such a native method, and the use of its way to the window. The webviewnative. XXXX ()
In typescript projects, there are no default wx and WebViewNative properties on window objects. We can explicitly define the wx and WebViewNative properties by referring to adding properties to the window global object:
interfaceWindow { wx? : {xxxx: Function} webviewnative? : {xxxx: Function}}Copy the code
If you can’t do this, you might write the assertion as any :(window as any).wx.xxxx()
You can see in the code snippet above that I have defined both attributes as optional in order to prevent direct chain calls without judgment in subsequent maintenance (iterations)
In the wechat environment, window.wx must exist, but WebviewNative must not exist. On the contrary, in other webviews, (see the previous hypothesis) Window. webviewNative must exist
In an interface, we can’t dynamically know and define which one exists
You could write it like this
if (typeof window.wx ! = ='undefined') {
window.wx.xxxx()
} else {
// not in wx
}
Copy the code
However, writing such expressions directly in if is too limited, or there are many ways to determine whether it is in the wechat environment, which will lead to a variety of judgments in the project, and the benefits of type predicates come out
function checkIsWxNativeAPICanUse(win: Window) :win is { wx: Exclude<Window['wx'].undefined> } & Window {
return typeof window.wx ! = ='undefined'
}
/ / use
if (checkIsWxNativeAPICanUse(window)) {
window.wx.xxxx()
}
Copy the code
conclusion
Reducing the use of ANY unnecessarily is both a good ts code habit and a reflection on the quality of your code
What other TS tips do you have
Original text: yzl. Xyz/Lin / 2021/05…