preface
TypeScript is a superset of the types of JavaScript that can be compiled to pure JavaScript. The compiled JavaScript can run on any browser. TypeScript compilation tools can run on any server and any system. I’ve been working with typescript for almost a year now, and I’ve had a lot of fun with TYPEScript. It certainly increases the standard and maintainability of our code, but it also adds to the development burden, but in the long run, I think it’s worth it. Suitable for new contact with Ts students but not so deep students, as for our VUE source analysis, I temporarily more than a week, in the later time will continue to talk about.
Type a,
1. unknow
Unknown is a type that cannot be defined in advance. In many scenarios, it can replace any functionality while retaining static checking.
const num: number = 10; (num as string).split(" ") // error The conversion of type "number" to type "string" may be wrong because the two types do not overlap sufficiently. If this is intentional, first convert the expression to "unknown". (num as unknown as string).split('')Copy the code
You can convert it to any type. The difference is that during static compilation, unknown cannot call any method, whereas any does.
const foo: unknown = 'string'; foo.substr(1); // Error: static check failed const bar: any = 10; bar.substr(1); // The Pass: any type is equivalent to abandoning static checkingCopy the code
One use case for unknown is to avoid static type checking bugs caused by using any as the argument type of a function:
function test(input: unknown): number { if (Array.isArray(input)) { return input.length; // Pass: in this code block, the type guard has recognized the input as an array type} return input.length; // Error: The input type is unknown. If the input parameter is any, the check will be abandoned and an error will be reported.Copy the code
2. enum
Enumeration can improve the readability of our code. For example, I need to send a type of answer to a question on the back end in my business. If I send a type of reply to a question, I need to send a 1. So we can define an enumeration, we need to pass a value for example if we want to pass a video, we can pass answerMessageType.video, and when we write the interface specification parameter type we can specify that type as AnswerMessageType, So you can’t pass a seven.
/ / export enum AnswerMessageType {text = 0, pictrue = 1, video = 2, voice = 3, file = 4, /** * Srceent Rock link */ srlink = 6}Copy the code
3. void
In TS, the void and undefined functions are highly similar, logically avoiding the error of accidentally using null Pointers. The biggest difference between void and undefined is that you can think of undefined as a subset of void, and use void instead of undefined when you don’t care about the return value. Let’s take an actual example from React.
// Parent.tsx const Parent: FC = () => { const getValue = (): number => { return 2 }; /* Const getValue = (): string => {return 'STR'}; Return <Child getValue={getValue} />} // child. TSX type Props ={getValue: () => void; Function Child({getValue}: Props) => <div>{getValue()}</div>Copy the code
The operator
1. Non-empty assertion operator!
The operator can be used in a variable name or the function name, used to highlight the corresponding element is null | undefined
function onClick(callback? : () => void) { callback(); // The argument is optional. After that, TS compiles without error}Copy the code
This symbol scenario is especially useful for scenarios where we already know that the null value will not be returned, thus reducing redundant code judgments, such as the React Ref. The following is a custom hook written by the author in his work. There are two divs on the left and two divs on the left, a picture on the left, and a paragraph of text on the right. The size of the picture on the left is uncertain according to the box on the right, and the size of the picture on the left is calculated according to the box on the right. To judge E.T. Arget! Or divRef current! To do a writing
export function useCalcImg() { const [maxWidth, setMaxWidth] = useState(0) const [maxHeight, setMaxHeight] = useState(0) const [imgWidth, setImgWidth] = useState(0) const [imgHeiht, setImgHeight] = useState(0) const imgRef = useRef(null) const divRef = useRef<HTMLDivElement>() const handleImgLoad = useCallback((e) => { let img = e.target as HTMLImageElement setImgWidth(img.naturalWidth) setImgHeight(img.naturalHeight) }, []) const calc = () => { if (maxWidth && imgWidth && imgRef.current) { let div = divRef.current setTimeout(() => { let { width, height } = Util.calc.fixedImgScale(imgWidth, imgHeiht, div.clientWidth, div.clientHeight) imgRef.current.width = width imgRef.current.height = height removeClass(imgRef.current, 'hidden') }, 100) imgRef.current.width = 100 } } const imgRefCallback = useCallback((img) => { imgRef.current = img }, []) useEffect(() => { calc() }, [imgRef, divRef, maxWidth, imgHeiht]) const refCallback = useCallback((e) => { divRef.current = e if (e) { const { clientWidth, clientHeight } = e setMaxWidth(clientWidth) setMaxHeight(clientHeight) } }, []) return { imgRefCallback, handleImgLoad, refCallback } }Copy the code
2. Optional chain operator?
Compared to above! Non-null judgment applied at compile time,? This is the run-time (and, of course, compile-time) non-null judgment that developers need most.
// For example, there is a parameter flag on the backend. If flag is present, flag is passed: 1; if data is not present, data is not passed? .flagCopy the code
? . Used to judge whether the left side of the expression is null | undefined, if it’s expression will stop running, can reduce a lot of our && operations.
So let’s say we write a, right? . B, the compiler automatically generates the following code
let b = a ! == null && a ! == void 0 ? a : 10;Copy the code
Operator
1. keyof
Keyof can get all the keys of a type and return a union type, as follows:
type Person = { name: string; age: number; } type PersonKey = keyof Person; / / PersonKey get type for 'name' | 'age'Copy the code
2. typeof
Typeof is the type that gets an object/instance, as follows
interface Person { name: string, age: number } const people: Person = { name: 'thl', age: 22 } const P = typeof people // { name: string, age: number | undefined } const me: typeof people = { name: 'wsy', age: 21}Copy the code
3. in
In can only be used in the definition of a type. You can iterate over enumerated types as follows:
Type TypeToNumber<T> = {[key in keyof T]: number}Copy the code
Keyof returns all key enumerations of the generic type T. Key is any custom variable name linked with in and wrapped around [] (this is a fixed collocation). Number to the right of the colon defines all keys to be of type number.
Const person: TypeToNumber< person > = {name: 21, age: 21} // [custom variable name in enum type]: typeCopy the code
Fourth, generics
Generics is a very important property in TS, as it serves as a bridge from static definition to dynamic invocation, as well as a metaprogramming of TS’s own type definitions. Generics are arguably the essence of t-type tools and the hardest part of the whole TS to learn. The basic use
Type Person<T> = const Person: Person<number> = {name: 'ww', type: Class People<T> {private type: T; constructor(type: T) { this.type = type; } // Const people: people <number> = new people <number>(20); Function swipe<T, U>(value: [T, U]): [U, T] {return [value[1], value[0]]; }Copy the code
Like deep cloning
export function deepCopy<T extends Record<any, any>>(data: T): T {
const t = typeOf(data)
let o
if (t === 'array') {
o = []
} else if (t === 'object') {
o = {}
} else {
return data
}
if (t === 'array') {
for (let i = 0; i < ((data as any) as any[]).length; i++) {
o.push(deepCopy(data[i]))
}
} else if (t === 'object') {
for (let i in data) {
o[i] = deepCopy(data[i])
}
}
return o
}
Copy the code
Advanced generics
1. Partial
What this tool does is make all properties in generics optional.
type Partial<T> = { [P in keyof T]? : T[P] }Copy the code
For example, the happy method can be left out
type Person = {
name: string
age: number
happy: () => void
}
const me: Partial<Person> = {
name: 'thl',
age: 22
}
Copy the code
2, Record > < K, T
This tool converts all property values in K to type T. It is often used to declare a normal object.
type Record<K extends keyof any,T> = {
[key in K]: T
}
Copy the code
Take a chestnut
Const me: Record<string, string> = {'name': 'THL ', 'tag':' THL '}Copy the code
3. Pick<T, K>
The purpose of this tool is to extract the list of K keys from the T type and generate a new subkey value pair type.
type Pick<T, K extends keyof T> = {
[P in K]: T[P]
}
Copy the code
Take a chestnut
interface Person { name: string age: number do: () = > void} type PeopleInfo = Pick < Person, 'name' | 'age' > / / will be the name and age are extracted from two types, don't have to redefine type const me: the Person {name: 'thl', age: 22}Copy the code
4: Exclude<T, U>
This tool returns the remainder of a T type that removes the intersection of the T and U types.
type Exclude<T, U> = T extends U ? never : T
Copy the code
Take a chestnut
type PersonOne = { name: string age: number sleep: () => void } type PersonTwo = { name: string age: number eat: () => void} type Person = Exclude<PersonOne, PersonTwo> type PersonDo = {sleep: () => void eat: () => void}Copy the code
5. Omit<T, K>
This tool can be thought of as a Exclude for key-value pairs, which removes key-value pairs of type T that contain K.
type Omit = Pick<T, Exclude<keyof T, K>>
Copy the code
Take a chestnut
type Person = Omit<PersonOne, 'age'>
const me: Person = {
name: 'thl',
sleep: () => console.log('i will')
}
Copy the code
6. ReturnType
This tool is to get the type of the return value corresponding to the T type (function) :
type ReturnType<T extends (... args: any) => any> = T extends (... args: any) => infer R ? R : any;Copy the code
Look at the source code is actually a little more, in fact, can be slightly simplified into the following appearance:
type ReturnType<T extends func> = T extends () => infer R ? R: any;
Copy the code
Take a chestnut
function foo(x: string | number): string | number {// Todo}
type FooTyp
e = ReturnType<foo>; // string | number
Copy the code
7. Parameters
This tool is to get the parameter type corresponding to the T type (function)
type Parameters<T> = T extends (... args:string[]) => any ? string[] : any;Copy the code
An example of an old rule
type Fn = (a: string, b: number) => void
type FnParams = Parameters<Fn>
Copy the code
In fact, there are some advanced types here is not a list, interested can go to the official website www.typescriptlang.org
conclusion
There are many skills in the use of Ts, which may not be easy to encounter in daily use, but we will learn a lot when we read some source code. Another problem that needs to be summarized is the difference between type and interface and how we choose. There is no difference in essence. Type is better than interface, and using & is less code
Type Person = {name: string age: number} type NewPerson = Person & {do: () => void} interface People {happyStatus: true eat: () => void} interface NewPeople extends People {name: string }Copy the code
In addition type have some interface could not do, such as using | for the combination of enumerated types, using typeof get defined type and so on.
If we want to add a custom property or method to the window object, we can just add the property based on its interface.
declare global { interface Window { MyNamespace: any; }}Copy the code
As a personal habit, I usually use type more
This is all the content of this article. At the end of next week, I may continue to summarize the vUE source series or analyze the source code of hook in React. It depends. Recently bought a elevation 4 ready to consolidate the foundation, brave Niuniu, not afraid of difficulties.