background
Ts has been using it for a year and, looking back, it’s not going so well. Take advantage of the Spring Festival holiday these two days have time, sorted out a few of their own feel need to pay attention to the situation, a review.
I learned Java and C# when I was in school, and did C# full-stack development for two years after graduation, so I have some experience with statically typed languages. Ts is slowly replacing JS because it is a statically typed language.
But TS is different from Java, essentially because it is a statically typed language that is compiled into weakly typed JS for execution. So, TS has compile time, not run time. Much of what follows is a manifestation of this characteristic.
[Personal reminder] I feel that TS has made a lot of complicated (or flexible) designs in order to better adapt itself to THE transformation of JS. I have not summarized in detail, but this feeling is very strong. So don’t worry if you find the TS too fussy in some ways, it may not be your problem, but its.
Anything good should be simple and clear.
A confusing type
If you ask, “How many types of variables are there for TS?” can you give a comprehensive answer? There are more types of TS than JS.
never
vs void
Just one feature to keep in mind: functions that return never must have an unreachable end, such as an infinite loop or an exception thrown.
function fn1(): never { while(true) { /*... */ } } function fn2(): never { throw new Error( /*... * /)}Copy the code
any
vs unknown
any
Syntax checking is ignored for any typeunknown
Unpredictable types that do not ignore syntax checking (this is the big difference)
const bar: any = 10; any.substr(1); // ok-any ignores all type checks const foo: unknown = 'string'; foo.substr(1); // (foo as string).substr(1) // OK // if (typeof foo === 'string') {foo.substr(1)} // OKCopy the code
Some actions that “trick” the compiler into checking syntax
It’s like telling the compiler, “Just do what I write, don’t worry about it too much, if anything happens, I’m responsible!”
The compiler doesn’t bother you anymore, it doesn’t do syntax checking, but you have to think about the consequences. Therefore, the following content please use with caution, do not use without brain.
@ts-ignore
Adding an @ts-ignore comment ignores the syntax check on the next line.
Const num1: number = 100 num1.substr() // Error syntax check Error const num2: number = 200 // @ts-ignore num2.substr() // Ok syntax check passedCopy the code
any
If TS is Journey to the West, any is Sun Wukong, free and unrestrained. You can learn about JOURNEY to the West from Sun Wukong. You can also learn about TS from Any.
But in the end, sun Wukong becomes a Buddha. Your any should also be interface or type.
Types of assertionsas
As stated at the beginning of this article, TS is only compile-time, not run-time. As is a classic example. You use AS to tell the compiler the type, and the compiler listens to you. But run it at your own risk.
function fn(a: string | null): Void {const length = (a as string).length console.log(length)} fn(' ABC ') // Ok // fn(null) // Error JS runs an ErrorCopy the code
Non-null assertion operator!
! Xx is used to exclude null undefined, which tells the compiler that xx is definitely not null or undefined
Similarly, errors can occur at runtime.
/ example / 1 function fn (a: string | null | undefined) {let s: string = "' s = a / / the Error s = a syntax check failure! // OK -- if a is null or undefined, s is null or undefined, which may cause a bug!! } // fn(null)Copy the code
// Example 2 type NumGenerator = () => number; function myFunc(numGenerator: NumGenerator | undefined) { const num1 = numGenerator(); // Error syntax check failed const num2 = numGenerator! (a); // OK} // myFunc(undefined) //Copy the code
// let a: number console.log(a) // error-variable 'n' is used before being assigned. Let b! : number console.log(b) // OK - `! 'means you're going to give b an assignment, and the compiler doesn't careCopy the code
Optional chain? .
? Will stop running some expressions immediately with null or undefined and return undefined [note] this will only work for NULL and undefined and will not work for something like 0 false ‘”. This is different from &&.
This operator, which looks like it’s getting a property, is conditional. That is, it’s one, right? : syntax sugar for ternary expressions. Since it has judgment logic, you can make mistakes if you don’t think it through properly.
/ / example 1 to obtain object attribute interface IFoo {a: number} function fn (obj: IFoo | null | undefined) : number | undefined { const a = obj? .a // ? Optional chain operator // First, if a is of type IFoo, print 100 // second, if a is null or undefined, Return a // fn({a: 100}) // fn(null) // fn(undefined)Copy the code
Function tryGetArrayElement<T>(arr? : T[], index: number = 0) { return arr? .[index]; } // "use strict"; // function tryGetArrayElement(arr, index = 0) { // return arr === null || arr === void 0 ? void 0 : arr[index]; / /}Copy the code
// Example 3 - For function calls type NumGenerator = () => number; function fn(numGenerator: NumGenerator | undefined | null) { const num = numGenerator? . (); Console. log('num', num) // undefined} // fn(null) // fn(undefined)Copy the code
I hate this kind of grammar candy. I think it’s better to write a few lines of logical judgment by myself. It’s simple, but it can be a burden to read, and simple code doesn’t necessarily mean readable code — of course, if people use it for a long time, they’re familiar with it, and maybe they don’t have to.
The type and interface
I’m still in a state of confusion. I feel that Type and Insterface have too much gray area, which leads us to use most of the time anyone. I don’t understand why TS would do this.
Based on my understanding of Java and C# over the years :(I don’t know if there have been any syntactic changes to Java C# in recent years)
- If you’re customizing a static type with only properties and no methods, use
type
- If you want to define a behavior (behavior definitely needs methods; attributes alone are not enough) that requires class implementation, use this
interface
Ts libraries lib.dom.d.ts and lib.es2015.d.ts source code are also used by interface. I was once very confused, see more, slowly accustomed to become a natural, but the problem has not been solved.
The problem wasn’t solved, but things had to continue to be done, and code had to continue to be written, so I just went with the crowd and tried to use interfaces.
private
和 #
Both represent private properties. Different backgrounds:
private
Is a syntax that has been present in TS since the beginning, and is currently present only in TS, not in the ES specification.#
Is the current proposal syntax of ES, then supported by TS 3.8. That is, both TS and ES are supported#
。
If it’s just for TS, it doesn’t matter which one you use. But as mentioned at the beginning of this article, TS only focuses on compile time, not runtime. So, you have to see the results of both compilations.
private
When you compile private, you lose the private feature. That is, if you execute (new Person()).name, the syntax check will fail, but the runtime will succeed. That is, private is just the syntax of TS, and when compiled into JS, it is invalid.
// ts source class Person {private name: string constructor() {this.name = 'zhangsan'}} class Person { constructor() { this.name = 'zhangsan'; }} * /Copy the code
#
(new Person()).name is not implemented at runtime. That is, # is the TS syntax, but it is also the ES proposal syntax, and cannot be invalidated after compilation.
However, the resulting “private” is done via WeekMap, so make sure your runtime environment supports ES6. WeekMap does not have a perfect Polyfill scheme, and forcing Polyfill can cause a memory leak.
// ts source class Person {#name: string constructor() {this.#name = 'zhangsan'}} var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, privateMap, value) { if (! privateMap.has(receiver)) { throw new TypeError("attempted to set private field on non-instance"); } privateMap.set(receiver, value); return value; }; var _name; class Person { constructor() { _name.set(this, void 0); __classPrivateFieldSet(this, _name, 'zhangsan'); } } _name = new WeakMap(); * /Copy the code
Function overloading
Function overloading in Java
Function overloading in Java is very easy to use, and very easy to understand, dumb-ass, easy to read. The following code defines four functions named test with different parameters. Just write the four functions and call them when you call them, and Java will match them automatically.
public class Overloading { public int test(){ System.out.println("test1"); return 1; } public void test(int a){ System.out.println("test2"); } public String test(int a,String s){ System.out.println("test3"); return "returntest3"; } public String test(String s,int a){ System.out.println("test4"); return "returntest4"; } public static void main(String[] args){ Overloading o = new Overloading(); System.out.println(o.test()); o.test(1); System.out.println(o.test(1,"test3")); System.out.println(o.test("test4",1)); }}Copy the code
Function overloading in TS
Ts function overloading, first write each case of the function header, and then write a uniform, compatible with all the above case of the function header. Finally, the function body handles the parameters itself.
Class Person {// class Person (): void test(a: number, b: number): number test(a: string, b: string): Test (a? Test (a? Test (a? Test)); : string | number, b? : string | number): Third, void | string | number {/ / If (typeof a === 'string' && typeof b === 'string') {return 'string params'} if (typeof a === 'number' && typeof b === 'number') { return 'number params' } console.log('no params') } }Copy the code
This is complex + ugly compared to Java syntax and completely against design principles. But why? In the end, ts only cares about compile time, not run-time — the original sin. Just think, if TS also designed to overwrite like Java, then compiled JS code will be messy. Because JS is weakly typed.
Notice the order in which functions are defined
The more accurate the parameters are, put them first.
/* Declare function fn(x: any): any; declare function fn(x: HTMLElement): number; declare function fn(x: HTMLDivElement): string; var myElem: HTMLDivElement; var x = fn(myElem); // x: any, wat?Copy the code
Do not write different overloads only for different trailing arguments; use optional arguments whenever possible.
/* error */ interface Example1 {diff(one: string): number; diff(one: string, two: string): number; diff(one: string, two: string, three: boolean): number; } /* OK */ interface Example2 { diff(one: string, two? : string, three? : boolean): number; }Copy the code
Dom-related types
The popularity of the Vue and React frameworks has turned most business developers into framework engineers instead of directly manipulating the DOM. But the Web is DOM based, so don’t forget it.
Js DOM manipulation is very simple, do not care about the type, directly access the properties and methods. But with TS, you have to worry about the relevant types of DOM operations.
Not only do we use TS, but when Microsoft designs TS, they also need to define the types of DOM manipulation and put them in the TS class library so that TS can be used in Web scenarios. These are defined in lib.dom.d.ts. P: There is also the ES syntax built-in library, also in the same directory.
PS: a mature and usable programming language, including the basic: syntax + library + compiler + runtime (or compiler and runtime together into an interpreter). Then there are the peripheral configurations of frameworks, tools, package managers, etc.
Node Element, etc
All of this is already out there, already defined by the W3C, so let’s just go over it. I think a picture can be well expressed, and you can refer to their RESPECTIVE MDN documents for details.
Event parameter type
Before USING TS, I didn’t pay much attention to the event parameter types (or saw them before and didn’t use them), but just grabbed the attributes and used them.
Document. The body. The addEventListener (' click ', e1 = > {/ / e1 constructor is what? }) document. The body. The addEventListener (' keyup, e2 = > {/ / e2 constructor is what? })Copy the code
So I checked the MDN document, in fact, it is very easy to understand, that is, different events, parameter types are not the same, of course, the attributes, methods are not the same. Here’s a list of all the common types that we refer to in the MDN document.
The event | The parameter types |
---|---|
click dbclick mouseup mousedown mousemove mouseenter mouseleave | MouseEvent |
keyup keyrpess keydown | KeyboardEvent |
Compositionstart compositionUpdate compositionEnd | CompositionEvent |
focus blur focusin focusout | FocusEvent |
drag drop | DragEvent |
paste cut copy | ClipboardEvent |
Their inheritance relationship is shown below. UIEvent represents some events triggered by the user in UI. Because events are triggered not only by users, but also by API scripts, a UIEvent should be taken out separately as a distinction.
conclusion
I think the point is that TS is a statically typed language, but it has to be compiled into js, a weakly typed language, for execution, so it can manage compile time, not runtime. This is the root of many problems.
It seems that the front-end community is slowly moving towards TS, so being able to use TS proficiently is an essential skill for a front-end person. I hope this article can bring you a little help.
Past review:
- Front-end Engineer: It’s the worst of times, it’s the best of times
- Meituan is cool, angry to brush 3000 interview questions reverse attack byte, tearful sharing face book
- 13 design patterns commonly used in Javascript
- Ali uploaded a “recruiter version of the front-end Vue interview booklet”, big factory interview no longer hit a wall, continuous update ~
- Analysis of real Questions for Front-end School Recruitment