THE LAST TIME
“
The last time, I have learned
[THE LAST TIME] has always been a series THAT I wanted to write, aiming to build on and revisit THE front end.
But also to their own shortcomings and technology sharing.
Please refer to the collection of the author’s articles for details:
- GitHub address: Nealyang/personalBlog
- Public number: full stack front end selection
preface
JavaScript is undoubtedly a very good language, but it also has many disadvantages, including some “bugs” left by the author’s design. Of course, the flaws outweigh the flaws
After all, JavaScript is a weakly typed language, and its biggest programming flaw compared to a strongly typed language is that it can lead to a loss of type thinking (advanced vocabulary, learned from geek time). The way we think determines our programming habits, the way we think determines our engineering quality, and the quality of engineering defines our capabilities. The most important thing in learning Typescript is the reinvention of our type thinking.
So Typescript, as I understand it, is not really a programming language, it’s just a shell of JavaScript. Of course, we can learn it as a language. There are a lot of articles on the web that either recommend or don’t recommend Typescript and so on and we’re not going to do anything about it here, learning or not learning, using or not using Typescript, pros and cons. Each to his own
Speaking of typescript (ts for short), ts is no stranger to typescript. More introductory ts articles and documentation are already out there. This article does not translate or transport apis or tutorial chapters. Just a summary of the list and to solve the confusion, the author in the process of learning TS had doubts. No way to the place, welcome everyone to comment on the area of active discussion.
Js to.ts; over!
But how come I can write TS, but I can’t read other people’s code? This!!!! It’s the barrier between entry and advancement. This is the purpose of this article.
Typescriptlang.org is the compilation environment for TS
Recommend the author to collect a few websites:
- Typescript Chinese website
- Understand Typescript in depth
- TypeScript Handbook
- TypeScript Mastery Guide
Below, one by one the difficulties are sorted out and broken one by one.
Indexable type
There is no need to describe the types of TS. Introduce indexable types of TS. To be precise, this belongs in the category of interfaces. Speaking of interfaces, we all know that one of the core principles of TS is to type check the structure that values have. It is sometimes referred to as a “duck type” or “structural subtype”. And the interface is the contract. Indexable types are also a representation of an interface, very useful!
interface StringArray {
[index: number]: string;
}
let myArray: StringArray;
myArray = ["Bob"."Fred"];
let myStr: string = myArray[0];
Copy the code
In the example above, we define the StringArray interface, which has index signatures. The index signature indicates that when StringArray is indexed by number, it returns a value of type String. Typescript supports two index signatures: strings and numbers. Both types of indexes can be used, but the return value of the numeric index must be a subtype of the return value type of the string index.
This is because when you index a number, JavaScript converts it to a string and then indexes the object. That is, indexing with 100 (a number) is the same as indexing with 100 (a string), so the two need to be consistent.
class Animal {
name: string;
}
class Dog extends Animal {
breed: string;
}
// Error: Use numeric string index, sometimes get completely different Animal!
interface NotOkay {
[x: number]: Animal;
[x: string]: Dog;
}
Copy the code
In the following example, the type of name does not match the type of the string index, so the type checker gives an error:
interface NumberDictionary {
[index: string]: number;
length: number; // Yes, length is number
name: string // Error, the type of 'name' does not match the type of the index type returned value
}
Copy the code
Of course, we can also make the index signature read-only to prevent index assignment
interface ReadonlyStringArray {
readonly [index: number]: string;
}
let myArray: ReadonlyStringArray = ["Alice"."Bob"];
myArray[2] = "Mallory"; // error!
Copy the code
Interface and type keywords
One of stackOverflow’s “thumbs up” responses was really thumbs up. typescript-interfaces-vs-types
Interface and type are very similar in meaning and function. Here are the two main differences:
Interface:
- With the same name
interface
Automatic aggregation can also be with the same nameclass
Automatic aggregation - Can only say
object
,class
,function
type
type
:
- More than just being able to represent
object
,class
,function
- Cannot duplicate the name (naturally does not exist the same name aggregation), extend the existing
type
You need to create a newtype
- Supports complex type operations
To illustrate some of the points listed above:
Objects/Functions
Both can be used to express Object or Function, but the syntax is a little different
interface Point{
x:number;
y:number;
}
interface SetPoint{
(x:number,y:number) :void;
}
Copy the code
type Point = {
x:number;
y:number;
}
type SetPoint = (x:number,y:number) = > void;
Copy the code
Other data types
Unlike interfaces, type can also be used to bid on other types, such as primitive data types, elements, unions, and so on
type Name = string;
type PartialPointX = {x:number; };
type PartialPointY = {y:number; };
type PartialPoint = PartialPointX | PartialPointY;
type Data = [number.string.boolean];
Copy the code
Extend
Both can be inherited, but the syntax is a little different. It is also important to note that interface and type are not mutually exclusive.
interface extends interface
interface PartialPointX {x:number; };
interface Point extends PartialPointX {y:number; };
Copy the code
type extends type
type PartialPointX = {x:number; };
type Point = PartialPointX & {y:number; };
Copy the code
interface extends type
type PartialPointX = {x:number; };
interface Point extends PartialPointX {y:number; };
Copy the code
type extends interface
interface ParticalPointX = {x:number; };
type Point = ParticalPointX & {y:number};
Copy the code
implements
A class that implements interface or type in exactly the same form. However, both classes and interfaces are considered static blueprints, so they cannot implement/inherit types of the union type
interface Point {
x: number;
y: number;
}
class SomePoint implements Point {
x: 1;
y: 2;
}
type Point2 = {
x: number;
y: number;
};
class SomePoint2 implements Point2 {
x: 1;
y: 2;
}
type PartialPoint = { x: number; } | { y: number; };
// FIXME: can not implement a union type
class SomePartialPoint implements PartialPoint {
x: 1;
y: 2;
}
Copy the code
A statement to merge
Unlike Type, interfaces can be defined repeatedly and are automatically aggregated
interface Point {x:number; };
interface Point {y:number; };
const point:Pint = {x:1.y:2};
Copy the code
only interface can
In real development, you sometimes encounter situations where an interface can express something but type cannot: attaching attributes to a function
interface FuncWithAttachment {
(param: string): boolean;
someProperty: number;
}
const testFunc: FuncWithAttachment = function(param: string) {
return param.indexOf("Neal") > - 1;
};
const result = testFunc("Nealyang"); // There are type reminders
testFunc.someProperty = 4;
Copy the code
& and | operators
Here we need to distinguish, | and & is not an operator. We can read as & to mean that all contracts must be satisfied at the same time. | said can only meet a contract.
interface IA{
a:string;
b:string;
}
type TB{
b:number;
c:number [];
}
type TC = TA | TB;// The key of the TC can contain ab or BC, and of course contain bac
type TD = TA & TB;// TD must contain ABC
Copy the code
Cross type
A crossover type, we can think of as a merge. Essentially, you combine multiple types into one type.
Man & WoMan
Copy the code
- Man and Woman at the same time
- Have both Man and Woman members
interface ObjectConstructor{
assign<T,U>(target:T,source:U):T & U;
}
Copy the code
Above is the source implementation of TS, let’s look at an example of our daily use
interface A{
name:string;
age:number;
sayName:(name:string) = >void
}
interface B{
name:string;
gender:string;
sayGender:(gender:string) = >void
}
let a:A&B;
// This is legal
a.age
a.sayGender
Copy the code
Note: 16446
T & never = never
Copy the code
extends
Extends is an extension, inheritance. In TS, the extends keyword can either extend or qualify an existing type. When extending an existing type, you cannot override a type conflict. For example, the key a of the base type is string and cannot be changed to number in the extended type.
type num = {
num:number;
}
interface IStrNum extends num {
str:string;
}
// This is equivalent to the above
type TStrNum = A & {
str:string;
}
Copy the code
In TS, we can also do triadic operations with condition types: T extends U? X : Y
type IsEqualType<A , B> = A extends B ? (B extends A ? true : false) : false;
type NumberEqualsToString = IsEqualType<number,string>; // false
type NumberEqualsToNumber = IsEqualType<number,number>; // true
Copy the code
keyof
Keyof is the index type operator. A type used to get a “constant”, meaning anything that can be determined at compile time, such as const, function, class, etc. It’s a one-way street from the actual running code to the type system. In theory, any run-time symbol name that is intended to be used by the type system must be typeof.
When class is used, the class name represents the instance type and typeof Class represents the class itself type. Yes, this keyword has the same name as the JS typeof keyword.
Given that T is a type, keyof T produces a type that is a combination of the attribute name string literal types of T.
Attention! The above T is a data type, not the data itself.
interface IQZQD{
cnName:string;
age:number;
author:string;
}
type ant = keyof IQZQD;
Copy the code
On vscode, we can see the ant inferred by ts:
Note that if T is a type with a string index, keyof T is a string or number type.
Index signature parameter type must be “string” or “number”
interface Map<T> {
[key: string]: T;
}
//T[U] is the index access operator; U is an attribute name.
let keys: keyof Map<number>; //string | number
let value: Map<number>['antzone'];//number
Copy the code
The generic
Generics might be a little bit of a hard thing to understand on the front end. In general, generics are defined as specifying a variable representing a type, substituting it for an actual type for programming purposes, and then substituting it with a type that is actually run or derived, so that a program using generics can actually adapt to different types. To put it bluntly, generics are a type constraint specification for data types that are not determined in advance, but are determined at the time of use.
Generics can be applied to functions, interfaces, types, or classes. Note, however, that generics cannot be applied to static members of a class
A couple of simple examples, just to get a feel for generics
function log<T> (value: T) :T {
console.log(value);
return value;
}
// Two calls
log<string[]>(['a'.',b'.'c'])
log(['a'.',b'.'c'])
log('Nealyang')
Copy the code
- Generic types, generic interfaces
type Log = <T>(value: T) => T
let myLog: Log = log
interface Log<T> {
(value: T): T
}
Let myLog: Log<number> = Log // Generics constrain the entire interface and must specify the type when implemented. If no type is specified, a default type is specified after the definition
myLog(1)
Copy the code
We can also think of generic variables as parameters of a function, just parameters of another dimension, parameters that represent types rather than values.
class Log<T> { // Generics cannot be applied to static members of a class
run(value: T) {
console.log(value)
return value
}
}
let log1 = new Log<number>() // The type of the passed generic that can be displayed when instantiated
log1.run(1)
let log2 = new Log()
log2.run({ a: 1 }) // It is possible to pass no type argument. When not specified, the value of value can be any value
Copy the code
Type constraint. An interface must be predefined
interface Length {
length: number
}
function logAdvance<T extends Length> (value: T) :T {
console.log(value, value.length);
return value;
}
// The input parameter must have the length attribute, no matter what type
logAdvance([1])
logAdvance('123')
logAdvance({ length: 3 })
Copy the code
Benefits of generics:
- Functions and classes can easily support multiple types, enhancing the extensibility of programs
- No need to write multiple function overloading, lengthy joint type declaration, improve code readability
- Flexible control of constraints between types
Generics are also very common within TS, especially for container classes. And for us, or to use more, more thinking, so that there will be a more profound experience. It’s also very helpful in shaping our type thinking.
A profound
function pluck<T.K extends keyof T> (o: T, names: K[]) :T[K] []{
return names.map(n= > o[n]);
}
interface Person {
name: string;
age: number;
}
let person: Person = {
name: 'Jarid'.
age: 35
};
let strings: string[] = pluck(person, ['name'.'name'.'name']); //["Jarid", "Jarid", "Jarid"]
Copy the code
“Pluck” is an analysis of the meaning of the method “Pluck” with the points we mentioned above
<T, K extends keyof T>
Constraint that this is a generic functionkeyof T
Is to take all constant keys in T (in this example call), i.e. :"name" | "age"
K extends keyof Person
Is the K is"name"
or"age"
- With the generic explanation above, look at the parameters
K[]
That is, it can only contain"name"
or"age"
An array of
- Now look at the return value
T[K][]
At the back of the[]
Array means array. whileT[K]
It goes under T of the objectkey
:K
thevalue
infer
The infer keyword first appeared in PR and represented type variables to be inferred from the extends condition statement
Introduced in TS2.8, this keyword is used to replace manually fetched types in conditional statements.
type PramType<T> = T extends (param : infer p) => any ? p : T;
Copy the code
In the above conditional statement, infer P means the function parameters to be inferred. If T can be assigned to (Param: Infer P) => any, the result will be (Param: Infer P) => any, or T.
interface INealyang{
name:'Nealyang';
age:'25';
}
type Func = (user:INealyang) = > void;
type Param = ParamType<Func>; // Param = INealyang
type Test = ParamType<string>; // string
Copy the code
Generic tools
Utility generics are just syntactic sugar implementations of generics. You can write it yourself. We can also find their definitions in lib.d.ts
Partial
Partial is used to make an attribute passed in optional.
Since the keyof keyword has been introduced. That’s all the keys you can use to get an object interface. Before we get to Partial, let’s look at the in operator:
type Keys = "a" | "b"
type Obj = {
[p in Keys]: any
} // -> { a: any, b: any }
Copy the code
Then look at the Partial implementation:
type Partial<T> = { [P inkeyof T]? : T[P] };
Copy the code
Keyof T retrieves the names of all attributes of T, and then in iterates, assigning the values to P, and finally T[P] retrieves the values of the corresponding attributes. : Changed to optional.
Required
Required makes the attribute passed in mandatory. The source code is shown below
type Required<T> = { [P inkeyof T]-? : T[P] };
Copy the code
Readonly
Change the attribute passed in to a read-only option, source code below
type Readonly<T> = { readonly [P in keyof T]: T[P] };
Copy the code
Record
This type can convert the value of all attributes in K to T type, source code implementation is as follows:
/ * *
* Construct a type with a set of properties K of type T
* /
type Record<K extends keyof any, T> = {
[P in K]: T;
};
Copy the code
The key can be set based on all possible values in K, and the type of value, for example:
type T11 = Record<'a' | 'b' | 'c', Person>; // -> { a: Person; b: Person; c: Person; }
Copy the code
Pick
Take a set of properties of K from T
/ * *
* From T, pick a set of properties whose keys are in the union K
* /
type Pick<T, K extends keyof T> = {
[P in K]: T[P];
};
Copy the code
Exclude
Exclude Removes a type that belongs to another type.
/ * *
* Exclude from T those types that are assignable to U
* /
type Exclude<T, U> = T extends U ? never : T;
Copy the code
Never is returned if T can be assigned to U, and T is returned otherwise. The result is to remove certain types of U from T
Here’s an example:
type T00 = Exclude<'a' | 'b' | 'c' | 'd'.'a' | 'c' | 'f'>; // -> 'b' | 'd'
Copy the code
Can see T is’ a ‘|’ b ‘|’ c ‘|’ d ‘, and then U is’ a ‘|’ c ‘|’ f ‘, returns the type of the new type can be U to remove, namely ‘b’ | ‘d’.
Extract
Extract (T) Extract (U) from T; Extract (U) from T;
/ * *
* Extract from T those types that are assignable to U
* /
type Extract<T, U> = T extends U ? T : never;
Copy the code
Demo:
type T01 = Extract<'a' | 'b' | 'c' | 'd'.'a' | 'c' | 'f'>; // -> 'a' | 'c'
Copy the code
Omit
A combination of Pick and Exclude to implement the function of ignoring some attributes of the object, source code is as follows:
/ * *
* Construct a type with the properties of T except for those in type K.
* /
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
Copy the code
Demo:
/ / use
type Foo = Omit<{name: string, age: number}, 'name'> // -> { age: number }
Copy the code
More tool generics
In fact, the common tool generics are probably the ones I have described above. For more tool generics, see lib.es5.d.ts.
After all… There’s really no point in moving a few paragraphs of statement.
Types of assertions
Assert this kind of thing should be used sparingly… For starters, type assertions are probably the fastest to master. After all, any is good
Typescript allows us to override its inferences (we wrote the code ourselves, after all) and then parse it according to our own custom types. This mechanism is called type assertion
const nealyang = {};
nealyang.enName = 'Nealyang'; // Error: 'enName' attribute does not exist in '{}'
nealyang.cnName = 'a 凨'; // Error: 'cnName' attribute does not exist in '{}'
Copy the code
interface INealyang = {
enName:string;
CnName:string;
}
const nealyang = {} as INealyang; // const nealyang = <INealyang>{};
nealyang.enName = 'Nealyang';
nealyang.cnName = 'a 凨';
Copy the code
A type assertion is a simple way to “correct” TS’s judgment about the type, but it’s up to you to correct it.
Two points need to be noted:
- Preemptive use of recommended type assertions
as
Keyword, rather than<>
To prevent ambiguity - Type assertions are not type conversions. Type assertions occur at compile time. Type conversions occur at run time
Function overloading
“
When I first started using TS, I was confused… Why is there such a trivial way to write function overload, optional argument it is not fragrant?
The basic syntax for function overloading:
declare function test(a: number) :number;
declare function test(a: string) :string;
const resS = test('Hello World'); // resS is inferred to be of type string;
const resN = test(1234); // resN is inferred to be of type number;
Copy the code
We said it twice, right? ! Why can’t I determine the type or optional arguments? And then I came across this scene,
interface User {
name: string;
age: number;
}
declare function test(para: User | number, flag? :boolean) :number;
Copy the code
In the test function, we probably intended to pass no flag when para is User and flag when para is number. TypeScript doesn’t know this. Flag also allows you to pass in para as User:
const user = {
name: 'Jack'.
age: Awesome!
}
// No error reported, but against the idea
const res = test(user, false);
Copy the code
Using function overloading can help us achieve:
interface User {
name: string;
age: number;
}
declare function test(para: User) :number;
declare function test(para: number, flag: boolean) :number;
const user = {
name: 'Jack'.
age: Awesome!
};
// bingo
// Error: Parameter mismatch
const res = test(user, false);
Copy the code
Some combat of Ts
I published two introductions about TS in the actual combat project on the official account before:
- How to decorate your Typescript with decorators?
- Rax +Typescript+hooks project Architecture Thinking on a Single page
reference
- The future of TypeScript
- Typescript Chinese documents
- Understand Typescript in depth
- The ultimate React component pattern in TypeScript 2.8
- TypeScript Cheat sheet
- High-level types
- TypeScript uses summaries in React
Study and communication
- Pay attention to the public number [full stack front selection], get good articles recommended every day
- Add wechat id: is_Nealyang (note source) to join group communication
Public account [Full stack front End Selection] | Personal wechat 【is_Nealyang】 |
---|---|