preface
TypeScript is a superset of JavaScript that gives JavaScript the features of a strongly typed language. Using TypeScript in a project exposes errors early in the development phase, and TypeScript retains JavaScript features and adds powerful features such as interfaces, generics, classes, and so on to make development easier. I made a lot of notes in the process of learning TypeScript. This article was generated during the process of sorting out TypeScript. I also hope to let more students know about TypeScript and help deepen my memory.
Data types in TypeScrip
TypeScript data types include all JavaScript data types. Enumerations, tuples, any, void, and other types are also provided. Here’s how to use these types in TypeScript.
Native data types in JavaScript
- Boolean
// Boolean
let bool: boolean = true;
Copy the code
- String
// String
let str: string = 'hello TypeScript';
Copy the code
- Number
- Like JavaScript, all numbers in TypeScript are floating point numbers
- In addition to supporting decimal and hexadecimal,
TypeScript
Binary and octal are also supported
// Number
let decLiteral: number = 10;
let hexLiteral: number = 0xf00d;
let binaryLiteral: number = 0b1010;
let octalLiteral: number = 0o744;
Copy the code
- Array
- An Array can be declared in two ways:
- First, an element type can be followed by [] to represent an array of elements of that type
- The second way is to use Array generics, Array< element type >
- An Array can be declared in two ways:
// First, the element type can be followed by [] to represent an array of elements of that type
let arr1: number[] = [1.2.3];
// The second way is to use Array generics, Array< element type >
let arr2: Array<number> = [1.2.3];
// Arrays support multiple element types
let arr3: (number | string) = [1.'2'.3];
let arr4: Array<number | string> = [1.'2'.3];
Copy the code
- Function
// Function
let add = (x, y) = > x + y;
Copy the code
- Object
// This can be defined, but an error will be thrown when accessing or modifying the attributes, because the x and y attributes do not exist on Object.
let obj: Object = {x: 1, y: 2};
console.log(obj.x); // Attribute 'x' does not exist on type 'Object'
// Complete the definition
let obj1: {x: number, y: number} = {x: 1, y: 2};
console.log(obj1.x); / / 1
Copy the code
- Symbol
// Symbol
let syb: symbol = Symbol('hello');
Copy the code
- Null and undefined
/ / null and undefined
let null: null = null;
let undefined: undefined = undefined;
Copy the code
The way we followed a variable with a type in the example above is called a type annotation. Variables that use a type annotation must be assigned to the type declared by the type annotation, otherwise TypeScript throws an error.
New TypeScript data types
- void
void
Represents no return value, or the return value isundefined
, usually used to declare the return value type of a function.- If a variable is declared as
void
Type, which can only be assigned tonull
withundefeated
.
// void
let add = (x: number, y: number) :void= > undefined; // The return value is undefined
let unusable: void = undefined;
unusable = 'hello'; // ts throws an error that cannot assign type "hello" to type "void"
Copy the code
- any
any
Can be assigned to dividenever
Outside any type.- Note: It can be used
any
, but not all of them are recommendedany
To define the type used in this wayTypeScript
It doesn’t make any sense.
// any
let any: any = 1;
any = '1';
any = null;
Copy the code
- never
never
A type represents the type of a value that never exists- return
never
A function must have an end point that cannot be reached, such as a function with an infinite loop, a function that always throws errors. never
Can only be assigned tonever
Itself.
// never
function loop() :never {
while(true) {}}function error(message: string) :never {
throw new Error(message);
}
Copy the code
- tuples
- A tuple type represents an array with a known number and type of elements. The elements need not be of the same type
- A tuple out of bounds throws an error
/ / tuples tuple
let tuple: [number.string] = [1.'2'];
tuple[2] = 2; // Cannot assign type "2" to type "undefined".
Copy the code
- The enumeration
- Enumerations fall into two types: numeric and string enumerations
- The value of an enumerator is read-only and cannot be modified
- The default is numeric enumeration, starting at 0 and increasing in ascending order
- Enumerator types fall into two categories:Constant enumerationwithComputational enumeration
- Constant enumerations: Constant enumerations are computed at compile time and stored as constants. Constant enumerations can be assigned in three ways:
- No initial value
- References to existing members
- Constant expression
- Computational enumerations: Enumerators that need to be evaluated. Computational enumerations are not evaluated at compile time and are kept until execution.
- The enumerator after a computational enumeration must be assigned
- Constant enumerations: Constant enumerations are computed at compile time and stored as constants. Constant enumerations can be assigned in three ways:
- Note that computational enumerations cannot be used in enumerations containing strings
- Note: Enumerations are usually used for permission and status judgments. Avoid “magic numbers” and improve readability and maintainability.
// Enumeration of digits, starting from 0 by default and increasing in ascending order
enum Color {
Red,
Green,
Blue
}
console.log(Color.Red) / / 0
console.log(Color.Red) / / 1
console.log(Color.Red) / / 2
// The value of a custom numeric enumeration
enum Alphabet {
A = 8,
B,
C = 2020
}
console.log(Alphabet.A) / / 8
console.log(Alphabet.B) / / 9
console.log(Alphabet.C) / / 2020
// Type protection
let year = Alphabet.C;
year = 'today'; // Cannot assign type "today" to type "Alphabet"
// Numeric enumeration supports bidirectional mapping
console.log(Alphabet.A) / / 8
console.log(Alphabet[8]) // A
// js implements bidirectional mapping
var Alphabet;
(function (Alphabet) {
Alphabet[Alphabet["A"] = 8] = "A";
Alphabet[Alphabet["B"] = 9] = "B";
Alphabet[Alphabet["C"] = 2020] = "C";
})(Alphabet || (Alphabet = {}));
// String enumeration
enum Message {
Fail = 'failure',
Success = 'success'
}
// Enumerator type
enum Library {
// Constant enumeration
BookName,
Year = 2020,
Count = BookName + Year,
// Computable enumeration
Number = Math.random(),
Size = 'How to be a Nuggets V6'.length // Enumerators after computational enumerations must be assigned
}
Copy the code
After reading the above, we have a general understanding of TypeScript data types. Some of you might be wondering, how do we write type annotations if we need to describe a complex data type? This comes down to content interfaces, how to use interfaces to describe complex data types.
interface
Interfaces are one of the core concepts in TypeScript and are used to constrain the structure of objects, functions, and classes.
- How do I declare an interface?
- The interface keyword can be used to declare an interface
- What attributes can an interface restrict?
- Optional properties:
x? : string
To specify whether the parameter is optional - Read-only properties:
readonly x: number
To specify whether the parameter is read-only
- Optional properties:
- How many types of interfaces are there?
- Object type
- Function types
- The parameter name of the function does not need to match the name defined in the interface, but the type at the corresponding position must be compatible
- The index type
- Mixed type
- Note: The interface hasDuck identificationFeatures.
- What is theDuck identification?
- A: A bird can be considered a duck if it walks like a duck, quacks like a duck and swims like a duck. This is the duck style, which we will illustrate below.
- What is theDuck identification?
Several types of interfaces
/** * Object type interface */
// Optional attributes and read-only attributes
interface Person {
name: string;
readonly age: number;
sex: 'boy' | 'girl', hobby? :string[]}let Tom: Person = {
name: 'Tom',
age: 3,
sex: 'boy'
};
Tom.age = 1; // Cannot assign to 'age' because it is a read-only property.
let Jerry: Person = {
name: 'Jerry',
age: 3,
sex: 'boy',
hobby: ['Have fun with Tom']}RenderList can be passed as long as it satisfies the convention of the Result interface. Extra codes and MSG do not matter if a bird walks like a duck, quacks like a duck, swims like a duck. * /
interface ListItem {
id: number;
name: string
}
interface Result {
list: ListItem[]
}
function renderList(result: Result) {
result.list.forEach((item: ListItem) = > {
console.log(item.id, item.name)
})
}
const data = {
list: [{
id: 1,
name: 'little red'
}, {
id: 2,
name: 'white'
}],
code: 1,
msg: ' '
};
renderList(data);
/** * Function type interface * The parameter name of a function does not need to match the name defined in the interface, but the corresponding type must be compatible */
let add: (x: number, y: number) = > number;
interface Add {
(x: number, y: number) :number;
}
// These two definitions are equivalent
// The parameter name of the function does not need to match the name defined in the interface
let add1: Add = (j: number, k: number) = > j + k;
// The type at the corresponding position must be compatible
let add2: Add = (j: string, k: number) = > j + k; // Cannot assign type "(j: string, k: number) => string" to type "Add". Parameter "j" and "x" have incompatible types.
/** * Index type interface * Index type has an index signature that describes the type of the object index and the corresponding index return value type. * Index type interface * Index type can be divided into string index and number index * String and number index can be used together, but the number index must be a subtype returned by the string index */
// Numeric index
interface StringArray {
[index: number] :string;
}
const myArra1: StringArray = ['1'.2]; // Type "number" cannot be assigned to type "string".
const myArray: StringArray = ['1'.'2'];
// String index
interface ListItem {
id: number;
name: string;
[x: string] :any;
}
// Here we use string to index any
let list: ListItem[] = [{
id: 1,
name: 'aa',
year: '2019'
}]
String and numeric indexes can be used together, but the numeric index must be a subtype returned by the string index
interface ArrayItem {
[x: string] :string;
[y: number] :number; // Number index type "number" cannot be assigned to string index type "string"
}
interface ArrayItem1 {
[x: string] :string;
[y: number] :string;
}
/** * Mixed type interface * Mixed type interface is a collection of function type interface and object type interface */
interface Lib {
(): void;
version: string;
doSomething(): void;
}
let lib: Lib = (() = > {}) as Lib;
lib.version = '1.0.0';
lib.doSomething = (a)= > {};
Copy the code
Type aliases and type assertions
- What is a type alias?
- Usually we useinterfaceDeclare the interface, butType the aliasCan do the same thing, even more easily.
- How do I declare a type alias?
- Type aliases are declared using the type keyword.
- How do I declare a type alias?
- Usually we useinterfaceDeclare the interface, butType the aliasCan do the same thing, even more easily.
- What is a type assertion?
- Sometimes you’re better than
TypeScript
Better understand the type of data, so you can use itTypes of assertionsTo indicate that you know the type format of the data.- How to useTypes of assertions?
- Consistent with JSX, use
The < types >
To declare type assertions. - use
as
Make type assertions. - Note: The first method conflicts with JSX in React. The second method is recommended.
- Consistent with JSX, use
- How to useTypes of assertions?
- Sometimes you’re better than
// Declare a function-type interface using an interface
interface Add {
(x: number, y: number) :number
}
// Declare a function-type interface using a type alias
type Add = (x: number, y: number) = > number;
// The above two declarations are equivalent
React initializes state. Setting the type is cumbersome. It is convenient to use type aliases
const initialState = {
page: 1,
pageCount: 15,
list: [{
id: 1,
name: 'Tom'}};type State = typeof initialState;
type State1 = {
page: number;
pageCount: number;
list: {
id: number;
name: string; } []; }// State and State1 are equivalent
/** * Type assertion * Type assertion can be declared in two ways: 1. with JSX general declaration, 2. Use the as keyword * In React. Use the second method */ as recommended
interface Obj {
x: number;
y: number;
}
let obj = {};
obj.x = 1; // Attribute 'x' does not exist on type '{}'
// 1. As stated by JSX
let obj1 = <Obj>{};
obj1.x = 1;
// 2. Declare with the as keyword
let obj2 = {} as Obj;
obj2.x = 1;
Copy the code
function
Functions in TypeScript behave almost the same as in JavaScript, except that TypeScript supports the following functions:
- Supports constraint parameter types and quantities
- The function must pass in arguments of the specified type and number, otherwise an error will be thrown.
- Support for defining the type of the return value of a function
- Indicates whether the function has a return value and the type of the return value
- Optional parameters are supported
- Optional parameters must come after required parameters
- Support for function overloading
TypeScript
By stating that overloading must be implemented in the broadest version of the type, you can interpret it as saying that the broadest version of the type needs to support all types of the previous version.
// Constraint parameter type and quantity
function add(x: number, y: number) {
return x + y;
};
add(1.2); / / 3
add(1.'2'); // Parameters of type "2" cannot be assigned to parameters of type "number"
add(1.2.3); // There should be two arguments, but get three.
/ * * * * optional optional parameters and joint type parameters in addition to the type parameters agreed, will be the default support undefined * * optional parameters are joint type joint type refers to the use "|" Settings supports a variety of types, subsequent content in detail * /
function add1(x: number, y? :number) {
return y ? x + y : x;
}
add1(1); / / 1
add1(1.2); / / 3
// Default parameters
function add2(x: number, y: number = 2020) {}
// Remaining parameters
function add3(x: number. rest:number[]){
return rest.reduce((pre: number, cur: number) = > pre + cur, x);
}
add2(1.2.3.4.5.6); / / 21
TypeScript specifies that overloading must be implemented in the broadest version of the TypeScript type. You can interpret this as meaning that the broadest version of the TypeScript type needs to support all types from previous versions. * /
function add4(. rest:number[]) :number;
function add4(. rest:string[]) :string;
function add4(. rest:any) {
let first = rest[0]
if (typeof first === 'string') {
return rest.join(' ')}if (typeof first === 'number') {
return rest.reduce((pre: number, cur: number) = > pre + cur)
}
}
add4(2020.1.17) / / 2038
add4('hello'.'TypeScript') // hello TypeScript
add4({x: 1, y: 2}) Type "{x: number; y: number; } cannot be assigned to arguments of type string
Copy the code
class
JavaScript itself has no concept of classes, and prior to ECMAScript 6 used functions and prototype-based inheritance to create reusable components. JavaScript introduces the class keyword in ECMAScript 6, which can be used for class-based object-oriented programming. But the essence of class is still function + prototype, which I won’t go into here. TypeScript classes include JavaScript classes and add new features such as member modifiers, abstract classes, polymorphism, and more.
Inheritance and member modifiers
TypeScript
What member modifiers and attributes are there?- public, public member
- Features: Accessible to all public members
- prviate, private member
- Feature: Private members cannot be called externally
- protected, protected member
- Features: Accessible only in a class and its subclasses.
- readonly
- Features: Read-only and cannot be changed
- static
- Feature: Can only be accessed by class name, not by subclass
- public, public member
TypeScript
Class attributes must have initial values.TypeScript
The default class attribute ispublic, public member
/** * inheritance and member modifier */
interface PersonBase {
name: string;
age: number;
sex: 'boy' | 'girl';
}
class Person {
name: string;
age: number;
readonly sex: string; // The property is read-only and cannot be changed
constructor({ name, age, sex }: PersonBase) {
this.name = name;
this.age = age;
this.sex = sex; }}class Man extends Person {
private wife: string; // Private members cannot be called externally
protectedpropertyList? :string[]; // Protected member, which can only be accessed in the class and its subclasses.
static weight: number = 120; // Can only be accessed by class name, not by subclass
constructor(personBase: PersonBase) {
super(personBase);
this.wife = 'Jilly';
this.propertyList = ['house'.'car'];
}
private getWife() {
return this.wife;
}
getWeight() {
return this.weight; // Property 'weight' is a static member of type 'Man'}}class Son extends Man {
constructor(personBase: PersonBase) {
super(personBase); }}const Tom = new Man({
name: 'Tom',
age: 18,
sex: 'boy'
});
const Child = new Son({
name: 'child',
age: 3,
sex: 'boy'
});
Child.sex = 'girl'; // Cannot assign to 'sex' because it is a read-only property.
console.log(Tom.propertyList); // Property "propertyList" is protected and can only be accessed in class "Man" and its subclasses.
console.log(Child.getWife()); // The property "getWife" is private and can only be accessed in the class "Man".
console.log(Man.weight); // Can only be accessed by class name, not by subclass
Copy the code
Abstract classes and polymorphism
- What is abstract class?
- Abstract classes are usually used as base classes to separate commonalities in multiple things and facilitate inheritance by other derived classes.
- What are the characteristics of abstract classes?
- Can only be inherited, not instantiated.
- How do I create abstract classes?
- Abstract class usage
abstract
The keyword defines abstract classes and methods.
- Abstract class usage
- What is polymorphism?
- Defined in a parent class, which can have different implementations in subclasses, this is polymorphic.
/** * Abstract classes can only be inherited, not instantiated. Abstract methods in abstract classes do not contain concrete implementations and must be implemented in derived classes */
// Implement an abstract class
abstract class Animal {
eat() {
console.log('eat');
}
// Implement an abstract method that contains no concrete implementation and must be implemented in a derived class
abstract sleep(): void;
}
const pig = new Animal(); // Cannot create an instance of an abstract class
class Dog extends Animal {
name: string;
constructor(name: string) {super(a);this.name = name;
}
sleep() {
console.log('dog sleep')}}let dog = new Dog('wang wang');
dog.sleep()
// The non-abstract class "Cat" will not implement the abstract member "sleep" inherited from "Animal".
class Cat extends Animal {
}
Copy the code
Classes and interfaces
- Interfaces can be inherited from one another using the extends keyword.
- Multiple interfaces must be separated by commas (,)
- When a class uses an interface, the implements keyword is used
- Interfaces and classes can inherit from each other
/** * Classes and interfaces * Interfaces can inherit from each other using the extends keyword. * To separate classes from multiple interfaces, use the implements keyword */
interface Animal {
eat(): void;
}
// Interface inherits interface
interface Felidae extends Animal {
run(): void;
}
interface Pets {
cute: boolean;
}
// Inherit multiple interfaces simultaneously
interface Cat extends Felidae, Pets {}
// Classes use interfaces
class Tom implements Cat {
cute = true;
eat(){};
run(){};
}
// Interface inherits classes
interface Jack extends Tom {}
Copy the code
The generic
- What are generics?
- The data format is not confirmed in advance; the specific type format is confirmed at use.
- Generic optimization:
- Functions and classes can easily support multiple attributes, 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.
- Note: Generics cannot be used on static members of a class
/** * Generics * Do not confirm the data format in advance, the specific type format is confirmed at use. * Generics cannot be used on static members of a class */
// A simple generic function
function log<T> (msg: T) :T {
return msg;
}
// Implement a generic interface
interface Log {
<T>(msg: T): T
}
// The two implementations are equivalent
// Two ways to use it
log<string> ('hello'); // First, tell the generic function what type of argument is passed
log('hello'); // Second, use TypeScript type inference to determine the type
let myLog: Log = <T>(msg: T) = > msg;
myLog<string> ('hello');
myLog('hello');
class Cat<T> {
static eat(name: T) {} Static members cannot reference class type parameters
}
Copy the code
Type protection mechanism
Type protection ensures that TypeScript variables are of a particular type in a particular block, so that properties and methods of the corresponding type can be safely referenced in a type-protected block.
/** * type protection mechanism * type protection mechanism can determine within a given block, can use the corresponding typeof methods and properties */ can use instanceof, typeof, in, hasOwnProperty, or combination judgment to determine the block */
class Pig {
edible: boolean = true;
}
class Cat {
cute: boolean = true;
}
function getAnimal(animal: Pig | Cat) {
const Animal = animal instanceof Pig ? new Pig() : new Cat();
if (Animal instanceof Pig) {
console.log(Animal.edible); // true
} else {
console.log(Animal.cute); // true}}Copy the code
High-level types
Cross type versus union type
- What is theCross type?
- Combining multiple types into a single type can be considered a collection of multiple types.
- How to implementCross type?
- use
&
Combine multiple types into a single type.
- use
- What is theThe joint type?
- Variables can be set to multiple types, and can be assigned according to the set type.
- How to implementThe joint type?
- use
|
To set multiple types, assignment can be based on the set type to assign.
- use
/** * A cross type merges multiple types into a single type, which can be considered a collection of multiple types. * Cross types use & to combine multiple types into a single type. * Union types can set variables to multiple types, and can be assigned according to the set type. | * joint types used to set up multiple types, assignment to assignment according to the type of set. * /
interface Dog {
run: (a)= > void;
}
interface Cat {
jump: (a)= > void;
}
// Cross types
let pet: Dog & Cat = {
run: (a)= > {},
jump: (a)= >{}};// Union type
let Sex: 'boy' | 'girl';
let Status: 'success' | 'fail' | 'loading'
Copy the code
The index type
- Index types allow static checking to cover “dynamic” scenarios where the type is indeterminate. For example, a common JavaScript pattern is to pick a subset of properties from an object.
keyof T
forIndex type query operatorT you can think of as any type and value.T[K]
forIndex access operator, like getting an object, there is a type of return value, and no error is thrown.
/** * Index type */
let obj = {
a: 1,
b: 2,
c: 3
};
// keyof T
interface Obj {
a: number;
b: string;
}
let key: keyof Obj; // "a" | "b"
// T[K]
let value: Obj['a']; // number
/** * T extends U * This function extends U * to find the index T contains in K[] and returns T[K]
function getValue<T.K extends keyof T> (obj: T, keys: K[]) :T[K] []{
return keys.map(key= > obj[key]);
}
console.log(getValue(obj, ['a'.'b'])); / / [1, 2]
console.log(getValue(obj, ['a'.'f'])); / / can't assign type "string" types "" a" | | "b" "c", "[1, undefined]
Copy the code
Mapping type
- What is theMapping type?
- A way to create a new genre from an old one. The new type converts the old type in the same way, such as making each property readonly or optional.
/** * mapping type * a way to create a new type from an old type. The new type converts the old type in the same way, such as making each property readonly or optional. * TypeScript itself provides a lot of kinds of mapping type, such as: Readonly, Partial, Pick, Record, and so on * interested students can view the node_modules/TypeScript/lib/lib. Es5. Which s file * /
interface Obj {
a: number;
b: string;
c: boolean;
}
/ / read-only
type ReadonlyObj = Readonly<Obj>
/ / is optional
type PartialObj = Partial<Obj>
// Extract the specified attribute
type PickObj = Pick<Obj, 'a' | 'b'>
type RecordObj = Record<'x' | 'y', Obj>
Copy the code
Conditions in the
- What is theConditions in the?
- As the name implies, it returns a type based on a condition.
- 2.8 the TypeScript
lib.d.ts
Some predefined conditional types have been added to:Exclude<T, U>
– fromT
The cull can be assigned toU
The type of.Extract<T, U>
Extract –T
Can be assigned toU
The type of.NonNullable<T>
– fromT
In rejectingnull
andundefined
.ReturnType<T>
Gets the function return value type.InstanceType<T>
Gets the instance type of the constructor type.
/** * Condition type */
// T extends U ? X : Y;
type TypeName<T> =
T extends string ? "string" :
T extends number ? 'number' :
T extends boolean ? 'boolean' :
T extends undefined ? 'undefined' :
T extends Function ? 'function' :
'object';
type T1 = TypeName<number>; // number
type T2 = TypeName<string[] >// object
// (A | B) extends U ? X : Y;
type T3 = TypeName<number | string[] >;// "number" | "object"
// Diff means to find values from T that do not exist in U, return never if they do not exist, return never if they do not exist
type Diff<T, U> = T extends U ? never : T;
type T4 = Diff<'a' | 'b' | 'c'.'a' | 'e'>
// Diff <'a', 'a', 'e'> | Diff <'b', 'a', 'e'> | Diff <'c', 'a', 'e'>
// never | 'b' | 'c'
// 'b' | 'c'
type NotNull<T> = Diff<T, undefined | null>;
type T5 = NotNull<string | number | undefined | null> // string | number
// Exclude<T, U>
// NotNullable<T>
// Extract<T, U>
type T6 = Extract<'a' | 'b' | 'c'.'a' | 'e'>; // a
// RenturnType<T>
type T7 = ReturnType<(a)= > string> // string
Copy the code
conclusion
This concludes the TypeScript three-step primer. Thank you for reading and correct any errors.
The first Flag of 2020 has also been implemented, and I’m going home on January 20, 2020. Although it took a lot of time and effort, it has given me a deeper understanding of TypeScript and a deeper impression. The next TypeScript 3-step configuration chapter and TypeScript 3-step engineering chapter are expected in March or April.
Tomorrow will go home for the New Year, in this advance I wish you digging friends: happy New Year, good health, all the best.