In the former
Any application that can be implemented in javascript will eventually be implemented in javascript.
In the actual project, when we call a function written by others, the function does not leave any write-off. At this time, we need to find out the meaning of the call parameter of this function, and we need to look inside the function.
Sometimes we maintain a public function, you sweat to optimize a parameter type, but don’t know how many references, is not very worried, you modify the error of other functions.
All of this is because javascript is a dynamically weakly typed language. They are very tolerant of the types of variables and do not create a structured contract between these variables and their callers. If you develop without type constraints for a long time, you will lose “type thinking” and develop bad programming habits, which is one of the shortcomings of front-end development. Thankfully, the open source community has been working to address this issue, with Facebook releasing Flow back in 2014 and Microsoft releasing Typescript 1.0 that same year. Both are committed to providing static type checking for Javascript, and now that the years have passed, Typescript is clearly evolving better.
What is TypeScript?
TypeScript is officially a superset of Javascript with a type system that can be compiled into pure Javascript. Here are three key points to note:
-
Type checking
TypeScript does strict static type checking at compile time, which means you can spot potential pitfalls at the coding stage.
-
Language extension
TypeScript will include features such as asynchronous operations and decorators from ECMASript 6 and future proposals, as well as borrowing features such as interfaces and abstract classes from other languages.
-
Tool attribute
TypeScript compiles to standard Javascript and runs on any browser or operating system without any runtime overhead. In this sense, TypeScript is more of a tool than a language.
Why use TypeScript?
Other benefits of using TypeScript include Visual Studio Code’s powerful auto-completion, navigation, and refactoring capabilities, which allow interface definitions to replace documentation directly, as well as improving development efficiency and reducing maintenance costs. More importantly, Typescript helps teams reinvent “type thinking.” Interface providers are forced to think about API boundaries. They go from being code writers to code designers.
What is a strongly typed language
In strongly typed languages, when an object is passed from a calling function to the called function, its type must be compatible with the type declared in the called function – Liskove,Zilles 1974
function Test1() {
Test2(a)
}
function Test2(b) {
// b can be assigned to a, and the program works fine
}
Copy the code
-
Strongly typed languages: It is not allowed to change the data type of a variable unless a cast is performed.
-
Weakly typed languages: Variables can be assigned different data types
Statically typed language: The types of all variables are determined at compile time
- The compile phase determines the attribute offset
- Use offset access instead of attribute name access
- Offset information sharing
- Extremely strict on type
- Find errors immediately
- Good runtime performance
- Since the document
Dynamically typed language: The types of all variables are determined at execution time
- Property offsets are calculated dynamically while the program is running
- Extra space is required to store attribute names
- A copy of the offset information for all objects is saved
- Very relaxed about types
- Bugs can be hidden for months or even years
- Poor runtime performance
- Readability is poor
TS compilation principle
Q: TypeScript can be translated into JS, but that doesn’t mean TS is a compiled language, right? So why compile? Why not choose translation, such words; So what does TS compilation look like?
A: Translation is a simple mapping, while compilation involves complex transformations and is more precise. Compilation broadly refers to the process of converting a source language into a target language. For example, the TypeScript compiler scans source code, converts it into an abstract syntax tree, and then converts it to JavaScript. Narrowly defined compilation refers to the translation of source languages into machine code. Languages that require such translation are often called compiled languages (such as C++), while TypeScript’s outgrowth JavaScript is interpreted.
Never and void
In JS, void is the operator that allows any expression to return undefined. Undefined is not a reserved word
// Undefined can be declaratively assigned
(function() {
const undefined = 0;
console.log(undefined)
})()
Copy the code
Void 0 ensures that our return value is undefined
// never
let error = () = > {
throw new Error('error')}Copy the code
A function that never returns a value if it throws an error returns a value of type never
Object type interface
In practice, the array returned by the back end might add some data
We find that TS does not report any errors because TS adopts a duck style, which is a dynamic language style. A more figurative way of saying this is that a bird can be considered a bird if it looks like a duck, walks like a duck and quacks like a duck. Back in TS, we are allowed to pass an object as long as it meets the necessary conditions of the interface, even if it passes extra fields through type checking.
But if we pass in object literals, TS checks for additional fields
If we use object literals to pass values, we use an assertion. Type assertion means we explicitly tell the compiler that the object literal is of type Result, so that the compiler can bypass type checking
Type assertions can also be written like this
However, we recommend using the first method because the following method can create ambiguity in React.
The index sign
We can also use index signatures
This is a string index signature, which means that using any string to index a List can result in any result. This allows lists to support multiple attributes.
Digital index
The implication is that if you index StringArray with any number you get a string structure
String index
The implication is that if you index an Item with any string you get a string
After this declaration, we can no longer declare a member of type number
Because the two signatures can be intermixed, for example, you can add a digital index signature to Item
So you can either index Item by number or you can index Item by string, but it’s important to note that the return value of the numeric index signature must be a subtype of the return value of the string index signature, because javascript does type conversion, converts number to string, This preserves type compatibility.
For example, if we change the return value of the digital index signature to number, then this is incompatible with string.
So take a type that is compatible with number, such as any.
Function type interface
Define it by Function
function fn1(x: number, y: number) {
return x + y
}
Copy the code
Defined by a variable
let fn2: (x: number, y: number) = > number
Copy the code
Defined by a type alias
type fn3 = (x: number, y: number) = > number
Copy the code
Defined by interface
interface fn4 {
(x: number, y: number): number
}
Copy the code
Mixed-type interface
Defines the interface
interface lib {
(): void // indicates that this class is a function that returns void
version: string, / / property
toDo(): void / / method
}
Copy the code
implementation
let lib: lib = (() = > {}) as lib
lib.version = '1.0'
lib.toDo = () = > {}
Copy the code
Create multiple instances
function getLib() {
let lib: lib = (() = > {}) as lib
lib.version = '1.0'
lib.toDo = () = > {}
return lib
}
let lib1 = getLib()
lib1.version
lib1.toDo()
let lib2 = getLib()
lib2.version
lib2.toDo()
Copy the code
Function overloading
class A {
sum(a: number, b: number) {
returna + b; }}class B extends A {
sub(a: number, b: number) {
returna - b; }}function maker() :B;
function maker(p: string) :A;
function maker(p? : string) {
if (p) {
return new A();
}
return new B();
}
const instane = maker();
instane.sub(1.2);
const instane2 = maker("ss");
instane2.sum(1.2);
Copy the code
When the TS compiler deals with overloads, it looks up a list of overloads and tries to match the first definition, and if it doesn’t match, it looks down, so we’ll put the easiest to match first.
assertions
type NumGenerator1 = () = > number;
function myFunc1(numGenerator1: NumGenerator1 | undefined) {
constnum1 = numGenerator1! (a);constnum2 = numGenerator1! (a); }Copy the code
Use assertions to make the compiler pass the check, though this is not recommended and overloading should be used instead
overloading
type NumGenerator2 = () = > number;
function myFunc2() :undefined;
function myFunc2(numGenerator2? : NumGenerator2) {
if (numGenerator2) {
const num1 = numGenerator2();
constnum2 = numGenerator2(); }}Copy the code
optional
type NumGenerator3 = () = > number;
function myFunc3(numGenerator3: NumGenerator3 | undefined) {
constnum1 = numGenerator3? . (); }Copy the code
class
In general, ts classes overwrite JS classes and introduce other new features
class Cat{
constructor(name:string) {
// this.name = name} name? : stringrun(){}}Copy the code
In both TS and ES, the properties of a class member are instance properties, not stereotype properties, and the methods of a class member are instance methods.
inheritance
class ChildCat extends Cat {
constructor(name: string, public color: string) {
super(name)
}
}
Copy the code
Be sure to call super in the constructor
The modifier
Public The default is public, meaning it is visible to everyone
Private Private member, can only be called from the class itself, cannot be called by instance, cannot be called by subclass
Protected members that can only be accessed from a class or subclass, not from an instance of the class
Constructor can also add protected to indicate that the class cannot be instantiated and can only be inherited
Readonly must be initialized, just like instance properties
In addition to class members, you can also add modifiers to constructor parameters, which automatically make the parameters properties of the instance and thus omit the class definition.
class ChildCat extends Cat {
constructor(name: string, public color: string) {
super(name)
}
}
Copy the code
Static: the static modifier of a class. Static members can also be inherited
An abstract class
There are no abstract classes in ES. This is ts’s extension of an abstract class, which can only be inherited but cannot be instantiated. In an abstract class, you can define a method that has a concrete implementation, so that subclasses don’t have to implement it and reuse the method. It is also possible to specify no concrete method implementation in an abstract class, which constitutes an abstract method. The nice thing about abstract methods is that you know there are other implementations in the subclass, so there’s no need to implement them in the superclass.
abstract class Animal {
eat() {
console.log('eat')
}
abstract sleep(): void
}
class Chicken extends Animal {
sleep() {
console.log('sleep')}}const chicken = new Chicken()
chicken.eat()
Copy the code
polymorphism
The so-called polymorphism is to define an abstract method in the parent class, in a number of subclasses have different implementation of the method, when the program runs, according to different objects, perform different operations, to achieve the binding of the runtime
class Cattle extends Animal {
sleep() {
console.log('Cattle sleep')}}const cattle = new Cattle()
const animals: Animal[] = [chicken, cattle]
animals.forEach(o= > {
o.sleep()
})
Copy the code
Chain calls
The whole point of chain calls is that the invoked method returns an instance of itself
class WorkFlow {
step1() {
return this
}
step2() {
return this}}new WorkFlow().step1().step2()
class Myflow extends WorkFlow {
next() {
return this}}new Myflow().next().step1().next().step2()
Copy the code
The relationship between type and interface
An interface can constrain what attributes a class member has and their types
interface Human {
name: string;
eat(): void
}
Copy the code
A class implementing an interface must implement all properties and methods declared in the interface
class Asian implements Human {
constructor(name: string) {
this.name = name
}
name: string
eat(){}}Copy the code
Interfaces can constrain only public members of a class
Inheritance of interfaces
Interfaces can inherit from each other like classes, and one interface can inherit from multiple interfaces
interface Man extends Human {
run(): void
}
interface Child {
cry(): void
}
interface Boy extends Man,Child {}
const boy: Boy = {
name: ' '.run() {},
eat() {},
cry(){}}Copy the code
As can be seen from interface inheritance, interface inheritance can be separated from reusable interfaces, or multiple interfaces can be combined into one interface
Interface inheritance class
Interfaces can inherit interfaces, but also inherit classes, which is equivalent to the interface to the class members are abstracted out, that is, only the class member structure, and no concrete implementation
class Auto {
state = 1
}
interface AutoInterface extends Auto {
}
Copy the code
So the AutoInterface implies the state property, and all you need to implement this AutoInterface is a class member and the state property
class C implements AutoInterface {
state = 1
}
class Bus extends Auto implements AutoInterface {}Copy the code
We don’t need to implement the state property in this example, because Bus is a subclass of Auto that naturally inherits the state property. It is important to note that when the interface removes the members of the class, it removes not only the public members, but also the private and protected members.
Generic functions and generic interfaces
A lot of times we want a function or a class that can support multiple data types and have a lot of flexibility
function print(value: string) :string {
console.log(value)
return value
}
Copy the code
Function overloading
function print(value: string) :string
function print(value: string[]) :string[]
function print(value:any) {
console.log(value)
return value
}
Copy the code
The joint type
function print(value: string | string[]) :string | string[] {
console.log(value)
return value
}
Copy the code
Any type
function print(value: any) {
console.log(value)
return value
}
Copy the code
The any type creates another problem. The any type loses some information, namely the constraints between types
The generic concept
Data types are not predetermined; the specific type is determined at the time of use
function log<T> (value: T) :T {
console.log(value)
return value
}
log<string[]>(['a'.'b'])
log(['a'.'b'])
Copy the code
We can not only define a function with generics, but also define a function type
type Log = <T>(value: T) = > T
const myLog: Log = log
Copy the code
A generic interface
This is equivalent to the way type aliases are defined, but currently the generics constrain only one function. Generics can also constrain other members
interface Log1 {
<T>(value: T): T
}
Copy the code
All members of the interface are then constrained by generics
It is important to note that when generics constrain the entire interface, we must specify a type at implementation time
let myLog1: Log2<number> = log
myLog1(1)
Copy the code
If you do not specify a type, you can specify a default type in the interface definition
interface Log3<T = string> {
(value: T): T
}
let myLog2: Log3 = log
myLog2('s')
Copy the code
Generic summary
Treat generic variables and function parameters the same; generics are just parameters of another dimension, parameters that represent types rather than values
Generic classes and generic constraints
A generic class
Much like generic interfaces, generics can constrain the members of a class, but it is important to note that generics cannot be applied to static members of a class
class Ame<T> {
run(value: T) {
console.log(value)
return value
}
}
const ame = new Ame<number>()
ame.run(1)
Copy the code
When no type argument is specified, value can be any value
const ame1 = new Ame()
ame1.run({a: 1})
ame1.run('ss')
Copy the code
Type constraints
interface Length {
length: number
}
function print<T extends Length> (value: T) :T {
console.log(value, value.length)
return value
}
Copy the code
The parameter needs to have a length attribute
print([1])
print('ss')
print({length: 1})
Copy the code
Benefits of generics
- Functions and classes can easily support multiple types, increasing the extensibility of programs
- No need to write multiple function overloading, lengthy joint type declaration, enhance code readability
- Flexible control of constraints between types