Recently, I have been working hard on TypeScript+React project. I have learned a lot of knowledge points from other existing projects, so I have summarized some knowledge points and provided a lot of convenience for development.
Non-null assertion operator!
Used to assert that the operation object is non-null and non-undefined. Specifically, x! Will exclude null and undefined from the x value field. Simply ignore null and undefined.
// Assertion operations are non-null and non-undefined
type ListNode = {
data: number next? : ListNode }// Used to add the next node
function AddNext(node: ListNode) {
if (node.next === undefined) node.next = { data: 0}}// Set the value of the next node
function SetNextValue(node: ListNode, value: number) { AddNext(node) node.next! .data = value// Declare node.next is not undefined
}
let list: ListNode = { data: 1 }
SetNextValue(list, 2)
console.log('list', list) // list { data: 1, next: { data: 2 } }
Copy the code
// 网上常见案例 忽略null和undefined
function myFunc(maybeString: string | undefined | null) {
/ / Type 'string | null | undefined' is not assignable to Type 'string'. (can't Type "string | null | undefined" assigned to Type "string".)
// undefined is not assignable to Type 'string'.
const onlyString: string = maybeString // Error
const ignoreUndefinedAndNull: string = maybeString! // Ok
}
Copy the code
// Ignore undefined when calling a function
type NumGenerator = () = > number
function myFunc(numGenerator: NumGenerator | undefined) {
// Object is possibly 'undefined'.
// Cannot invoke an object which is possibly 'undefined'.
const num1 = numGenerator() // Error
constnum2 = numGenerator! (a)//OK
}
Copy the code
Non-empty assertion operators are removed from compiled JavaScript code, so be careful when you actually use them! Non-empty assertions are inherently unsafe, subjective errors, and from a defensive programming point of view, it’s not recommended to use non-empty assertions because you use them, so you don’t get an error at compile time, but you get an error at run time.
Optional chain operators? .
Returns properties or methods of the object that are not null or undefined (advantage: saves code to determine if the object is empty)
interface Foo {
[key: string]: {
baz: () = > void}}let foo: Foo = {
bar: {
baz() {
console.log('this is function baz')}}}// Convert to JavaScript
// let newFoo = (foo === null || foo === undefined) ? undefined : foo.bar.baz()
letnewFoo = foo? .bar.baz()Copy the code
1. If foo.bar is null or undefined, access will still fail. .bar? .baz() 2. JavaScript && operator false (”, 0, NaN, false, undefined, null)? If the value is false (NaN, false, undefined, null), empty string and 0 have data 3. Can be used with arrays (eg. Arr? . [0]) method (eg. Log? .(the log method prints the description if it exists)
Null-value merge operator??
Variables are null or undefined. The following defaults
let foo: null = null
let bar = (): string= > {
return 'this is function bar'
}
// Convert to JavaScript
// let newFoo = (foo ! == null || foo ! == undefined) ? foo : bar()
let newFoo = foo ?? bar()
console.log('newFoo', newFoo) // newFoo this is function bar
Copy the code
?? The difference between and | |
// When localstorage. volume is set to 0, the page is set to 0.5
let volume = localStorage.volume || 0.5
// When localstorage. volume is set to 0, the page is set to 0
let volume = localStorage.volume ?? 0.5
Copy the code
?? Directly with && and | | operator when used as inappropriate This kind of situation will be thrown SyntaxError
/ / can not be used in the case of not use parentheses "| |" and "??" Operation.
null || undefined ?? 'foo' // Error
// Can't mix "&&" and "??" without parentheses Operation.
true && undefined ?? 'foo' // Error
// Change to
(null || undefined)??'foo'
Copy the code
With optional chain operators? The relationship.
Null-value merge operator for null and undefined, optional chain operator? The same is true. The optional chain operator is useful for accessing objects whose attributes may be NULL or undefined
interface Customer {
name: string city? : string }let customer: Customer = {
name: 'xiaoming'
}
letcustomerCity = customer? .city ??'Unknown city'
Copy the code
Private field #XXX
class Person {
// Special identifiers are only available for ECMAScript 2015 and later.
#name: string;
constructor(name: string) {
this.#name = name;
}
greet() {
console.log(`Hello, my name is The ${this.#name}! `); }}let semlinker = new Person("Semlinker");
semlinker.#name
Copy the code
Cross type &
Combine multiple types into a single type
interface Button {
type: string
text: string
}
interface Link {
alt: string
href: string
}
const BottonLink: Button & Link = {
type: 'danger'.text: 'Jump to Baidu'.alt: 'Jump to Baidu'.href: 'http://www.baidu.com'
}
Copy the code
Joint type |
Indicates that its type is connected to any one of multiple types
interface Button {
type: 'default' | 'primary' | 'danger'
text: string
}
const btn: Button = {
type: 'danger'.text: 'button'
}
Copy the code
Condition types (U? X: Y) the same syntax rules as ternary expressions
Type index keyof
Key gets the associative type of the key in an interface like Object.key
interface Button {
type: string
text: string
}
type ButtonKeys = keyof Button
/ / equivalent type ButtonKeys = 'type' | 'text'
Copy the code
Type constraint extends
In class, it inherits and in generics, it constrains generics
Tip: If you want to use a class interface, you need to implement the interface with implements. In addition, an interface can also use an interface, and extends the interface.
type BaseType = string | number | boolean
// The range of the generic T is BaseType. Arg parameter value types can only be BaseType
function Copy<T extends BaseType> (arg: T) {
return arg
}
Copy('this is function Copy')
Copy the code
// extends is often used with keyof to get the value of an object but the object is uncertain
const list = {
name: 'xiaoming'.age: 18
}
function getValue<T.P extends keyof T> (obj: T, key: P) :T[P] {
return obj[key]
}
console.log('getValue', getValue(list, 'name')) // getValue xiaoming
Copy the code
Type mapping in
Mapping of main types, traversing keys of existing interfaces or traversing cross types
Tool type Readonly Example
type Readonly<T> = {
/ / keyof T get a joint types' name '|' age
/ / P keyof equivalent to perform in a forEach logic traversing the 'name' | 'age
readonly [P in keyof T]: T[P]
}
interface obj {
name: string
age: string
}
type ReadOnlyObj = Readonly<obj> // Name age in obj is read-only
Copy the code
Partial
Properties defined in an interface type become optional
// Source code implementation
type Partial<T> = {
[P inkeyof T]? : T[P]; };Copy the code
Required
Properties defined in an interface type become mandatory
// Source code implementation
type Required<T> = {
[P inkeyof T]-? : T[P]; };Copy the code
Through the -? Remove? From optional attributes Makes a property optional to mandatory
Readonly
Properties defined in an interface type become read-only
// Source code implementation
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
Copy the code
Record<K extends keyof any, T>
The type that takes two type variables Record generates has property values that exist in type K extends Keyof any extends Keyof any what is keyof any? Is type K was roughly constraints in string | number | symbol just object index types, namely type K can only be specified for the several types, according to the following scenario can be better understood
Scene 1: Constructing an object array frequently in business code But the array is not convenient to index So we will sometimes bring out a field of an object as an index to construct a new object Suppose you have an array of goods list To be found in the list of goods commodities called xx We tend to iterate through way set in finding more cumbersome In order to facilitate We’re going to rewrite this array as an object
interface Goods {
id: number
name: string
price: number
url: string
}
const goodsMap: Record<string, Goods> = {}
const goodsList: Goods[] = [{
id: 1.name: 'xiaoming'.price: 100.url: 'www.baidu.com'
}]
goodsList.forEach(item= > goodsMap[item.name] = item)
console.log('goodsMap', goodsMap)
// xiaoming: { id: 1, name: 'xiaoming', price: 100, url: 'www.baidu.com' }
Copy the code
Scenario 2: Used for interface Response type declaration
type Car = 'Audi' | 'BMW' | 'MercedesBenz'
type CarList = Record<Car, { price: number }>
const car: CarList = {
'Audi': { price: 20 },
'BMW': { price: 30 },
'MercedesBenz': { price: 40}}console.log('car', car)
// car {
// Audi: { price: 20 },
// BMW: { price: 30 },
// MercedesBenz: { price: 40 }
/ /}
Copy the code
Pick<T, K extends keyof T>
The generic T checks out the specified properties and forms a new object type scenario: Todo(preview is just the finished state of the title required) Simple understanding of extracting the desired properties from an object
interface Todo {
title: string
completed: boolean
description: string
}
type TodoPreview = Partial<Pick<Todo, 'title' | 'completed'>>
const todo: TodoPreview = {
title: 'clean room',}Copy the code
Exclude<T, U>
Property to exclude types from the generic T that can be assigned to the generic U
type num = 1 | 2 | 3
type numExclude = Exclude<num, 1 | 2>
const numList: numExclude = 3
Copy the code
interface Worker {
name: string
age: number
email: string
salary: number
}
interface Student {
name: string
age: number
email: string
grade: number
}
type ExcludeKeys = Exclude<keyof Worker, keyof Student>
// Select * from Student where Worker salary does not exist
let ExcludeKeysList: ExcludeKeys = 'salary'
Copy the code
In contrast to Pick, Pick is used to Pick out attributes we need to care about, and Exclude is used to Exclude attributes we don't need to care about. Exclude is rarely used on its own and can be combined with other types to achieve more complex and useful functions
Extract<T, U>
Extract a type from the generic T that can be assigned to the generic U
type num = 1 | 2 | 3
type numExclude = Extract<num, 1 | 2>
const numList: numExclude = 1 // 1 or 2
Copy the code
Omit<T, K extends keyof any>
Extract the attribute types from the generic T that are not in the generic K and form a new object type
interface IUser {
name: string
age: number
address: string
}
type IUserOmit = Omit<IUser, 'name' | 'age'>
// Ignore the name and age attributes in the IUser interface
let iUserOmit: IUserOmit = {
address: 'shenzhen'
}
console.log('iUserOmit', iUserOmit) // iUserOmit { address: 'shenzhen' }
Copy the code
NonNullable
Exclude null and undefined from the generic T
type U = NonNullable<'name' | undefined | null>;
let text: U = 'name'
Copy the code
Parameters
any> ConstructorParameters
any> ReturnType
any> InstanceType
any> and other tool types. Tool types greatly improve the scalability of types and facilitate reuse. If there is any problem above, please correct it and modify it in time. There are more useful methods, please give more advice!