An overview of the
- TS is a programming language based on JS
- Solve the problem of JS type system
- TS greatly improves the reliability of your code
Key issues
- JS own type system problems
- How to solve this problem with some excellent technical solutions
- TS is just one of the languages we’ll be dealing with in this process
- Because TS is currently the ultimate solution to this problem, we’ll focus on it
- In addition, some other related technical solutions will also be introduced
Contents summary
- Strong and weak types
- Static versus dynamic typing
- JS own type system problems
- TS language specification and basic use
Strong and weak types
- A noun commonly used to distinguish between different programming languages
- Strong versus Weak typing (type safety)
- Static versus dynamic typing (type checking)
- Type safety
- Strong vs. weak
- Strongly typed: a linguistic constraint that a function’s argument types must be exactly the same as its parameter types
class Main { static void foo (int num) { System.outprintln(num); } public static void main(String[]) { Main.foo(100); / / 100 Main.foo("100"); // error "100" is a string Main.foo(Integer.parseInt("100")); // ok}}Copy the code
- Weak typing: There is no restriction on the type of argument at the language level
function foo (num) { console.log(num) } foo(100) // ok foo('100') // ok foo(pareseInt('100')) // ok Copy the code
- Because this kind of strong and weak type is not the definition of an authority at all, and there is no specific rule, so there are different understandings of the details of this kind of definition
- But on the whole, the way people define it is to describe:
- Strong types have stronger type constraints
- There are few constraints in weak types, right
- One of my favorite sayings is:
- Arbitrary implicit type conversions are not allowed in strongly typed languages
- Weakly typed languages allow arbitrary implicit type conversions
console.log('100' - 50) / / 50 console.log(Math.floor('foo')) // NaN console.log(Math.floor(true)) / / 1 Copy the code
- Variable types are allowed to change at any time, not strong and weak type differences
- Python, for example, is strongly typed, but its variable types can change at any time
- This may be a bit of a misrepresentation in many sources, as pythPN is said to be a weakly typed language, which it is not
- Strong vs. weak
Static versus dynamic typing
- Type checking
- Static versus dynamic typing
- Static typing: when a variable is declared, its type is unambiguous and cannot be changed after the declaration
- Dynamic typing: a type can only be identified at runtime, and the type of a variable can change at any time
- In a dynamic language, variables are untyped and the values they hold are typed
var foo = 100 / / number type foo = 'bar' / / string console.log(foo) Copy the code
- Static versus dynamic typing
JS type system features
- JS is a weakly typed and dynamically typed language
- The language’s own type system is weak, and even we can say that JS has no type system
- This characteristic of language could be called petulance!
- JS is a particularly flexible language because it has almost no type constraints
- But behind the surface, what’s missing is the reliability of the type system. Every time we encounter a variable in our code, we have to worry about whether or not it’s the type I want
- The overall feeling could be called: unreliable!
- Why isn’t JS strongly typed or statically typed
- Related to the background of JS, JS applications in the early days did not expect to develop to today’s scale, relatively simple, maybe dozens of lines of code or more than 100 lines of code can complete the function
- In this case, the limitations of the type system are redundant or cumbersome
- JS is a scripting language, the characteristics of scripting language is: no need to compile directly in the runtime environment to run
- In other words: JS doesn’t have compilation, so it doesn’t make sense to design a statically typed language because static typing requires compilation checks at compile time, whereas JS doesn’t have one
- So JS is a more flexible and changeable weak type dynamic language
- There was no problem at the time, and it was even an advantage at the time, but now the scale of front-end applications is completely different. There are massive applications everywhere, so JS code is more and more complex, and the development cycle is longer and longer. In this case, the advantage of the previous has become a disadvantage
- Related to the background of JS, JS applications in the early days did not expect to develop to today’s scale, relatively simple, maybe dozens of lines of code or more than 100 lines of code can complete the function
Weak type problems
- Problem exceptions are not discovered until run time
const obj = {}
/** * obj does not have this method, but it can be written syntactically, only at runtime error * that is, in weakly typed languages such as JS, we have to wait until runtime to find type exceptions in the code ** /
obj.foo() // TypeError: obj.foo is not a function
/** * If we do not execute this method immediately, but execute it at a certain time, the program will not be able to find the exception at first run, and will not throw an error until after the code is executed. This is left to the code * * in strongly typed languages where we call a non-existent member of the object, this is syntactically correct, without having to wait for the collection to run * */
setTimeout(() = > {
obj.foo() //TypeError: obj.foo is not a function
}, 1000)
Copy the code
- If the type is not clear, the function function may change
function sum (a, b) {
return a + b
}
console.log(sum(100.200)) / / 300
console.log(sum(100.'200')) / / 100200
/ * * * this is because uncertainty caused by type a typical problem * * we can through the agreed way to circumvent this problem, but there is no guarantee of agreement, especially in many collaborative development * * we cannot guarantee that everyone to follow all the provisions of the * * and we were in a strongly typed language, This situation is completely avoided because in strongly typed languages, we require numbers to be passed in, and passing in strings is an error * */
Copy the code
- An incorrect use of an object indexer
const obj = {}
obj[true] = 100
console.log(obj['true'])
/** * We want to create an object and assign it to the indexer ** The property name of the object can only be a string or ES6 Symbol ** but since JS is weakly typed, we can use any type of value in the indexer as the property name of the object. Internally it will automatically be converted to a string * * We're using a Boolean as the property name, which will eventually be converted to a string of the form true * * If we don't know that the property name of an object will automatically be converted to a string, This may feel strange * * the root cause of this oddity may be that we are using an arbitrary weakly typed language. In a strongly typed language this problem may be avoided * * because in a strongly typed language it explicitly has typing requirements, which are not syntactically valid * */
Copy the code
- This is just the tip of the iceberg for weak typing
- The disadvantages of weakly typed languages are very obvious, only in the case of small amount of code can be avoided by convention, but for some large projects with a long development cycle, this kind of gentleman’s agreement still has some hidden dangers, only in the grammar level of mandatory requirements can provide more reliable protection
- Strongly typed language code has a significant advantage in terms of code reliability, as it is possible to eliminate a large number of possible type exceptions in advance, rather than waiting for slow debugging during runtime
The advantage of strong typing
- Mistakes are exposed earlier
- Eliminate a large percentage of type exceptions early in the coding phase
- The code is smarter, the code is more accurate
- The one thing developers need the most
function render (element) { // element. /** * This is because there is no way to infer what type of element this element is ** so there is no way to know which members it contains ** Only memory can access the members of the object ** This also leads to problems with misspellings and names * * in strongly typed languages, the compiler, at all times, knows which type it is, so it can provide more accurate intelligence * */ } Copy the code
- Refactoring is more robust
- When you make a disruptive change to your code, such as deleting a member of an object or changing the name of an existing member
const util = { aaa: () = > { console.log('util func')}}/** * this object aaa method if used in many places, we can not modify ** because JS weak type language, modify the name of this attribute, many places use the name of the previous, even if there is an error, will not immediately show the ** strong type language. An error is immediately reported whenever a property name changes, so it is easy to locate all references and then modify * */ or even tools that automatically modify * */ all references to members of the object Copy the code
- Reduce unnecessary type judgments
- Strongly typed languages reduce some of our typing at the code level
function sum (a, b) { if (typeof a === 'number' || typeof b === 'number') { throw new TypeError('arguments must be a number')}return a + b } Copy the code
TS language specification and basic use
TS overview
- A superset (extension and extension) language based on JS
- Superset: some extension features are added to the original JS base
- What’s added is a more powerful type system and support for new ES features
- It will eventually compile to the original JS
- Advantages of the type system in TS
- We have experienced all of them in Flow, and the two are very similar, nothing more than to help us avoid type anomalies that may occur in the development process, and to improve the efficiency and reliability of our code
- New feature support
- ES has iterated many useful new features in recent years, but there are often compatibility issues in older environments. TS supports automatic conversion of these new features, so new features can be used immediately in TS
- Even if we don’t need such a strong typing system, it’s a good idea to use ES’s new features through TS
- We used Babel to convert some of the new features in JS. In fact, TS is similar to Babel in this respect, because TS can finally choose the lowest version of ES3 encoding, so the compatibility is particularly good
- Since TS is eventually compiled into JS to work, TS can be used for development in any JS environment, such as traditional browser applications, Node applications, and React.native applications
- Compared with Flow before, TS as a complete programming language, more powerful function, ecology is more sound, more perfect, especially for development tools!
- Many large projects are beginning to use TS development
- Angular
- Vue. Js 3.0
- TS – Second language in the front-end domain
- Small project – need flexibility, can choose JS itself
- Big projects – everyone suggested using TS
- disadvantages
- The language itself adds a lot of concepts
- Interface, generics, enumeration……
- Adding these concepts will increase the cost and time of learning, but TS is progressive
- Incremental: Even if we don’t know any features, we can immediately write TS code according to the JS standard syntax. In other words, we can use it as JS, and then learn a feature and use a feature
- For projects with short cycles, TS will increase some costs
- Because when you write a lot of type declarations early in the project, like objects, like functions, you have a lot of type declarations to write
- If it is a large project with long-term maintenance, this cost is nothing, and most of the time, it is forever, so the advantages of TS to us far outweigh the disadvantages. Right
- The language itself adds a lot of concepts
- Overall, TS will become a necessary language as our front-end evolves
TS Quick use
- The installation
- Instructions:
- yarn init -yes || npm init -y
- yarn add typescript –dev || npm i typescript -d
- Yarn TSC file name | | TSC file name
- Since TS itself is a module of NPM, it can be installed globally, but considering the problem of project dependence, it is more reasonable for us to install it in the project
- Instructions:
- At the end of the installation, the module will add a TSC command to our.bin directory on node_modules
- Function:
- Help us compile the TS code
- Start by checking for type usage exceptions in your code
- Remove extension syntax such as type annotations
- Automatic conversion of ES new features
- A more powerful type system
- Help us compile the TS code
- Function:
TS Configuration file
- The TSC command can be used not only to compile a specific TS file, but also to compile an entire project or project
- Before compiling, create a configuration file
- yarn tsc –init || tsc –init
- In this file, there is only one property called compilerOptions by default
- This property is a set of configuration options for the TS compiler
- Most of them are commented out, and there is a brief explanation of each option
- The most commonly used option
- Target – Sets the ES standard used by compiled JS
- Module — How will the output code be modularized
- Outdir — The folder to which the compiled results are output
- RootDir — The folder where the source code (TS) is located
- SourceMap – Enabled source mapping allows us to use sourceMap to debug TS source code during debugging
- Strict — Turn on all strict checking options, and the type checks become very strict
- Note:
- After we have the tsconfig.json configuration file, we can use this configuration file when we use the TSC command
- However, if you still use TSC to compile a specific file, the configuration file will not take effect. The configuration file will only take effect when you run TSC directly to compile the entire project
- Direct TSC generates not only a JS file, but also a corresponding sourceMap file
Primitive data type
- JS six primitive data types in TS basic application
// Raw data type
const a: string = 'foobar'
const b: number = 100 // NaN Infinity
const c: boolean = true // false
/** * In TS, empty ** is allowed, but this is an error because of the difference between strict mode and default mode ** requires strict to be turned off, and this is not an error ** in non-strict mode, String Number Boolean can be empty, strict mode is not allowed * * strict mode is enabled on all strict mode options, If we just want to check that our variables cannot be empty * * we can use strictNullChecks - check that variables cannot be empty * */
// const d: string = null
/ * * * void - a null value, generally in the function has no return value when used to tag function return value type * * only null/undefined strict mode, only for undefined * * /
const e: void = undefined
const f: null = null
const g: undefined = undefined
/** * can only store values of type Symbol() **
// const h: symbol = Symbol()
Copy the code
Standard library declaration
- Built-in object types
- Above we tried to use the global Symbol function. Creating a Symbol will cause an error
- Why is that?
- Symbol is actually a built-in JS standard Object, just like Array, Object property is the same, but Symbol is added to ES6, for this built-in Object, in fact, it has its own type, and these built-in types have been defined in TS for us
- Solution:
- Change target to ES2015
- The lib option specifies the standard library we reference
- An error occurs when you open console in file 01
- The console object is provided by the BOM object in the browser, and the lib we just set is ES2015 only, so all the standard libraries are overwritten, and all the default libraries need to be added back
- TS classifies the BOM/DOM into a DOM standard library
- An error occurs when you open console in file 01
- The standard library
- The declaration file corresponding to the built-in object
- To use built-in objects in code, you must refer to the corresponding standard library, otherwise TS will not find the corresponding type, and an error will be reported
Chinese error message
- TS supports multilingual error messages. By default, an error message language is selected based on the language Settings of the operating system and development tools
- Use –locale zh-cn when using the TSC command
yarn tsc --locale zh-CN || tsc --locale zh-CN
Copy the code
Scope problem
- In the process of learning TS, we will definitely involve trying some different features of TS in different files. In this case, we may encounter the same variable name in different files
// const a = 123
/** * const a: 123 * Cannot redeclare the block-scoped variable "a". Ts (2451) * 02- Original data type. Ts (2, 7): "A" is also declared here. * * /
Copy the code
- To solve
- Self-calling function
(function () { const a = 123}) ()Copy the code
- Using export, that is, ESmodules, allows the file to be exported as a file module, which has its own module scope
const a =123 export {} Copy the code
- This kind of problem is usually not used in real development, because in most cases, each file will work as a module, but we will inevitably use some duplicate variables in each case
The Object type
- In TS, Object does not refer only to Object types, but to all non-primitive types
- Objects, arrays, functions
- To restrict object types in TS, we should use more specialized interfaces, which we will cover in detail
- There are only two things we need to know here
- The object type does not refer only to objects, but to other types besides the original type
- Object type constraints, we can use this syntax like object literals, but the more professional approach is to use interfaces
export {} // Just for scope, not for real development
const foo: object = function () {} // {} [] function(){}
/** * If we need a normal object type, we use a literal-like syntax to mark the ** constraint object obj must have a property of foo, which must have a value of number. The structure of the assigned object must be exactly the same as the structure of our type, no more or less * *. This means that if one attribute is added, the syntax will report a type error * * */
const obj: { foo: number, bar: string } = {foo: 123.bar:'TS'}
Copy the code
An array type
- TS defines arrays in exactly the same way as Flow defines arrays in two ways
- Use Array generics
- Use element type + []
// An array of pure numbers const arr1: Array<number> = [1.2.3] const arr2: number[] = [1.2.3] Copy the code
- Advantages of strong typing in TS
// function sum ( ... args ) {
// return args.reduce((prev, current) => prev + current, 0)
// }
/** * In JS, we need to worry about the type of argument sum receives **. Most of the time, we need to add a bunch of judgments to make sure that each argument is number **. In TS, we just need to add a number array type annotation to the type ** /
function sum (. args: number[]) {
return args.reduce((prev, current) = > prev + current, 0)}// sum(1, 2, '3'
Copy the code
A tuple type
- Special data structures
- Tuple – an array that specifies the number of elements and each element type
- The element types of each element do not have to be identical; in TS you can use a syntax similar to array literals to define tuple types
- Typically used to return multiple return values in a function
- React useState hook returns a tuple type
- The object.entries () method in ES2017 takes an array of keys from an Object, and each key is a tuple because it is of a fixed length
export {}
const tuple: [number, string] = [1.'hhh']
// Only one number and string can be stored
// The elements of a tuple can be accessed using array subscripts
// const age = tuple[0]
// const name = tuple[1]
// The array structure can also extract each element
const [age, name] = tuple
Object.entries({
foo: 123.bar: 456
})
Copy the code
Enumerated type
- In the process of application development, we often use some values to represent a certain state
- The characteristics of
- A set of values can be given a more understandable name
- An enumerated value, with only a few fixed values, has no possibility of going out of range
- Enumerations are a common data structure in many traditional programming languages, but they do not exist in JS
- Many times we need to implement enumerations using an object emulation
const PostStatus = {
Draft: 0.Unpublished: 1.Published: 2
}
const post = {
title : 'hello TS'.content: 'TS is a typed superset of JavaScript'.status: PostStatus.Draft // 2 // 1 // 0
}
Copy the code
- With a special enumeration type in TS we can declare an enumeration using the keyword enum
enum PostStatus {
Draft = 0,
Unpublished = 1,
Published = 2
}
const post = {
title : 'hello TS'.content: 'TS is a typed superset of JavaScript'.status: PostStatus.Draft // 2 // 1 // 0
}
Copy the code
- Pay attention to the point
- The assignment sign is used instead of the colon
- Enumeration types can only be specified without an assignment number. If not specified, they will be accumulated from 0 by default.
- If you specify a specific value for the first member of the enumeration, the value will be accumulated on that basis
- Enumerations can have values other than number, or they can be strings, which are string enumerations
- Since strings cannot increment like numbers, enumerations of strings require us to manually initialize each member with an explicitly initialized value
- String enumerations are not common
// enum PostStatus { // Draft, // Unpublished, // Published // } // enum PostStatus { // Draft = 6, // Unpublished, // Published // } enum PostStatus { Draft = 'a', Unpublished = 'b', Published = 'c' } enum PostStatus { Draft, Unpublished, Published } const post = { title : 'hello TS'.content: 'TS is a typed superset of JavaScript'.status: PostStatus.Draft // 2 // 1 // 0 } Copy the code
- There’s one more thing we need to know about enumerations
- Enumeration types invade our runtime code
- In other words: it affects the results of our compilation
- Most of the types we use in TS will eventually be removed when compiled and converted, but enumerations will not, and will eventually be compiled as bidirectional key-value objects
- Bidirectional key-value pairs – values can be obtained by keys, and keys can be obtained by values
- The purpose is
- Enumeration names can be dynamically retrieved from enumeration values, meaning that the corresponding names can be retrieved from the code by means of indexers
- We recommend constant enumerations if you are sure that you will not use indexers to access enumerations in your code
- The use of constant enumerations is to add a const before the keyword enum
Function types
- Limits the input and output of a function, that is, parameters and return values
- There are two ways functions can be defined in JS
- Function declaration
- Functional expression
- So what we need to understand here is how do functions constrain types in both ways
export {}
// function fnuc (a: number, b: number): string {
// return 'func'
// }
// Limit the return value to string; The argument must be exactly the same, from type to number
// fnuc(1, 2)
// This parameter is optional
// function fnuc (a: number, b? : number): string {
// return 'func'
// }
// fnuc(1)
// Alternatively, use the default value of the parameter, or make it optional
// function fnuc (a: number, b: number = 100): string {
// return 'func'
// }
// fnuc(1)
// Both optional and default arguments must appear at the end of the argument list
// Arguments are passed by position. If the optional argument comes before the required argument, the required argument will not get the correct argument
// Any argument
function fnuc (a: number, b: number = 100. rest: number[]) :string {
return 'func'
}
fnuc(1)
// Function expression
const func1 = function (a: number, b: number) :string {
return 'func1'
}
/** * The function expression will eventually be placed in a variable, and the variable that accepts the function should also have a type ** Generally, TS can infer the type of our variable from our function expression ** If we pass a function as an argument, * * is as a callback function this way as in this case, the callback function we must to regulate the callback function the parameters of the type * * this kind of circumstance can use similar way to show our arrow function parameters can accept what kind of a function * * when defining interfaces is often used in this way * * /
Copy the code
Any type
- Due to the weak typing nature of JS, many of the built-in apis support accepting arguments of any type
- TS is based on JS, so it is inevitable that you will need a variable to receive any type of data in your code
- Note:
- The any type is still dynamic and can accept any type of value, as well as other types of values at run time, just like normal JS variables
- Since it can store any type of value, TS does not do type checking on any, which means that we can still call any member on it as we would on JS, syntactically
- But it also has type safety issues, so it’s easy not to use this type
function string (value: any) {
return JSON.stringify(value)
}
string('string')
string(100)
Copy the code
Implicit type inference
- In TS, if we do not explicitly mark a type with a type annotation, then TS will infer the type of the variable based on its usage – implicit type inference
export {}
let age = 18// TS determines the number type
// age = 'tri' // Cause: age has been identified as number
// This usage is equivalent to annotating age with number
// Mark it as any when no inference can be made, as in:
let foo
foo = 18;
foo = 'string'
foo = true
Copy the code
- Although implicit type inference is supported in TS and can help simplify some of our code, we still recommend that you add an explicit type to every variable if possible, so that we can understand our code more intuitively later
Types of assertions
- In some special cases, TS cannot infer the specific type of the variable, but we, as developers, can know exactly what type the variable is based on the usage of the code. Right
// Assume from an explicit interface
const nums = [110.120.119.112]
const res = nums.find(i= > i > 0)
/** * we know that the return value must be the ** of a number, but we infer that the return value must be the ** of number or undefined ** We can then assert that the res is a * */ of type number
Copy the code
- Way of asserting
- Use the AS keyword
- Use the < >
const num1 = res as number /** * the compiler knows that num1 is a number ** / const num2 = <number>res /** * It works the same way, but there is a slight problem with Angle brackets ** when we use JSX in our code **
will cause syntactic conflicts with JSX tags ** As is recommended ** / Copy the code - Note:
- Type assertion is not a conversion, it is not a conversion from one type to another, because conversion is a concept of code at run time, our local type assertion is only a concept during compilation, when the code is compiled, the assertion does not exist
interface
- It can be understood as a specification or contract, and is an abstract concept that can stipulate the structure of an object. When we use an interface, we must follow all the conventions of the interface
- In TS, the most intuitive embodiment of the interface is that you can specify which members of an object should have, and what are the types of these members
export {}
interface Post {
/** ** can be separated by commas, but the standard is a semicolon, which can also omit ** /
title: string;
content: string
}
function pointPost (post: Post) {
console.log(post.title)
console.log(post.content)
}
/** * This function has some requirements on the object, it must have the title and content attributes ** but this requirement is actually invisible, there is no explicit expression ** in this case can use the interface to express the constraint ** /
pointPost({
'title': 'hi, TS'.'content': 'hi'
})
Copy the code
- In a word: interface is used to constrain the structure of the object, an object to achieve an interface, he must have all the members of the interface
Interface added
- There are also special uses for members of conventions in interfaces
- Members of the optional
- If we are in an object and one of our members is optional, we can use a feature called optional members to constrain the interface of the object
- This usage is equivalent to marking its type with a specified type or undefined
interface Post { title: string; content: string; subtitle? : string }const hello:Post = { 'title': 'hi, TS'.'content': 'hi' } Copy the code
- A read-only member
- After initialization, it cannot be modified again
interface Post { title: string; content: string; subtitle? : string; readonly summary: string }const hello:Post = { 'title': 'hi, TS'.'content': 'hi'.'summary':'Not modifiable after initialization' } // hello. Summary = 'HHHHHHHH' // Error Copy the code
- Members of the dynamic
- It is generally applicable to some objects with dynamic members, such as the cache object in the program, which will appear some dynamic key values during running
interface Cache { [key: string]: string // Key is not fixed, string is the type annotation of key, and the outer string is the value set to the dynamic property } const cache: Cache = {} cache.foo = 'value' cache.foo = '123' Copy the code
- Members of the optional
Basic use of class
- Classes
- Describes the abstract characteristics of a specific class of transactions
- For example, mobile phone is a class, and its feature is that it can make and receive phone calls and send and receive text messages. Under this type, there will be some subclasses, which will definitely meet all the characteristics of the parent class, and then add some additional features. For example, smart phone can use some apps in addition to making and receiving phone calls and sending and receiving text messages
- You can’t use the class directly, but you can use the specific transaction of the class, like the smartphone in your hand
- The same is true of classes, which can be used to describe the abstract members of a specific object. Before ES6, JS was implemented through function + prototype simulation, but after ES6, JS has a special class
- In TS, in addition to all the functionality of classes used in the ES standard, additional functionality and usage have been added, such as special access modifiers for class members, and the concept of abstract classes
class Person {
/** * In TS, a class attribute must have an initial value. It can be assigned ** after = or initialized ** in the constructor
name: string // = 'initial value'
age: number / / = 123
constructor (name: string, age: number) {
/** * In TS we need to explicitly declare some attributes ** in the type, rather than dynamically adding ** / to the constructor directly through this
this.name = name
this.age = age
}
}
Copy the code
- Class attributes must be declared in the type before they are used. The purpose is to make some type annotations for our attributes. In addition, we can declare some methods for this class according to the syntax in ES6
Class access modifier
- Private – marked as a private property, accessible only from within the class
export {}
class Person {
name: string
private age: number // Annotated as private and accessible only inside the class
constructor (name: string, age: number) {
this.name = name
this.age = age
}
}
const tom = new Person('tom'.18)
console.log(tom.name)
// console.log(tom.age) // Error
Copy the code
- Public – marked as a public member, default in TS!
export {}
class Person {... private age: number// Annotated as private and accessible only inside the class. }const tom = new Person('tom'.18)
// console.log(tom.age) // Error
Copy the code
- Protected — protected from external access
export {}
class Person {... protected gender: boolean ... }const tom = new Person('tom'.18)
console.log(tom.gender) // Error, cannot be accessed externally
Copy the code
-
The difference between private and protected
- Protected only allows access to the corresponding member in this class
export {} class Person { public name: string // Annotated as public member, default in TS! private age: number // Annotated as private and accessible only inside the class protected gender: boolean constructor (name: string, age: number) { this.name = name this.age = age this.gender = true}}class Student extends Person { constructor(naem: string, age: number) { super(name, age) console.log(this.gender) // It can be accessed}}Copy the code
-
Function:
- Controls the accessibility level of members in some classes
-
Note:
- For access modifier to the public by default constructor, if set to private, this type cannot be instantiated outside, also can’t be inherited, this kind of situation we can only within the class to add a static method, and then in a static method to create the instance of type, because private only allow internally to visit
class Student extends Person { private constructor(naem: string, age: number) { super(name, age) console.log(this.gender) // It can be accessed } static create (name: string, age: number) { return new Student(name, age) } } // const jack = new Student() const jacked = Student.create('jack'.18) Copy the code
- If the type in the constructor is protected, such a type cannot be instantiated externally, but it is allowed to be inherited compared to private
Class read-only property
export {}
class Person {
public name: string
private age: number
protected readonly gender: boolean
constructor (name: string, age: number) {
this.name = name
this.age = age
this.gender = true
}
sayHi (msg: string): void {
console.log(I was `The ${this.name}.${msg}`)}}const tom = new Person('tom'.18)
console.log(tom.name)
tom.gender = false
Copy the code
Classes and interfaces
- Interfaces are a little more abstract than classes
- Before we went on to take cell phone example to compare, we say that a mobile phone is a type, the type of the instance can be calls to send and receive text messages, because of the characteristics of the mobile phone this class is like this, but we can not only for the phone only mobile phone, and machine also can call me before, but the machine does not belong to this category, mobile phone but a separate category, Because he is not able to send and receive SMS, in this case, there will be a common features between different classes and class, for these the characteristics of the public, we usually use the interface to abstract, mobile phones can be understood as, mobile phone can also answer the call, because it implements this protocol, machine can also make a phone call, because he also implements this protocol, here said the agreement, It’s called an interface in the program
export {}
interface Eat {
eat (food: string): void
}
interface Run {
run (distance: number): void
}
class Person implements Eat.Run {
eat (food: string): void {
console.log('Eat gracefully:${food}`)
}
run (distance: number): void {
console.log('Walking upright:${distance}`)}}class Animal implements Eat.Run {
eat (food: string): void {
console.log('Oink oink eat:${food}`)
}
run (distance: number): void {
console.log(Crawl ` :${distance}`)}}Copy the code
An abstract class
- Somewhat like interfaces, they can also be used to constrain subclasses to have a certain member
- An abstract class can contain some concrete implementation, whereas an interface can only be an abstraction of a member and contains no concrete implementation
- Generally, it is recommended to use abstract classes for large categories, such as the animal class, which should be abstract, because what we say is only a general reference, and not specific enough, there must be some more detailed categories below it
abstract class Animal {
eat (food: string): void {
console.log('Oink oink eat:${food}`)
}
abstract run (distance: number): void
}
// Once defined as an abstract class, it can only be inherited and cannot be instantiated using new
class Dog extends Animal {
run (distance: number): void {
console.log('Four Corners crawl',distance)
}
}
const d = new Dog()
d.eat('dog')
d.run(100)
Copy the code
The generic
- When we define a function, interface, or class, we do not specify a specific type, but when we use it, we specify a characteristic of the specific type
- In the case of functions, generics are when we declare a function, we don’t specify a specific type, and when we call it, we pass a specific type, in order to maximize the reuse of our code
export {}
// Create an array of the specified length
// function createNumberArray (length: number, value: number): number[] {
// const arr = Array
(length).fill(value)
// return arr
// }
// const res = createNumberArray(3, 100)
function createArray<T> (length: number, value: T) :T[] {
const arr = Array<T>(length).fill(value)
return arr
}
const res = createArray<number>(3.100)
const res1 = createArray<string>(3.'100')
Copy the code
- Conclusion:
- Generics are simply a way of changing a type that we can’t define to a parameter that we can pass as we use it
Type declaration
- In actual project development, we will definitely use some third-party NPM modules, which are not necessarily written in TS, so the members it provides will not have a strongly typed experience
- Namely a member at the time of definition for some reason lead to no clear type, and then when we used alone for him to make a clear statement that the reasons of the existence of this usage is to consider compatible with some of the common JS module, as the community TS is very strong, at present, most of the commonly used NPM module has provided the corresponding statement, We just need to install its corresponding type declaration module
- If there is no corresponding declaration, we can only declare the corresponding module type through the DECLARE statement
import {camelCase} from 'lodash'
declare function camelCase (input: string) :string
const res = camelCase('hello typed')
Copy the code