First, common skills

1. Function overload

export function util(str: string) :string
export function util(str: number) :number
export function util(str: string | number) :number | string {
  return str;
}

const a: string = util('a');
const b: number = util(1);
Copy the code

2. Capture variable types

The typeof a variable is captured through the typeof keyword

let a = 123;
let b = { x: 0.y: 1 };

type A = typeof a; / / number type
type B = typeof b; // { x: number, y: number }
Copy the code

3. Function bindingthiscontext

Specify the context of the current function by binding the function’s first argument, this (official documentation)

const obj = {
  say(name: string) {
    console.log('Hello,', name); }}// Bind the current function context with the first argument this
function foo(this: typeof obj, str: string) {
  this.say(str);
}
Copy the code

4. Never use

Never represents types that Never occur (official documentation), such as returns from throw functions, returns from dead-loop functions

// Throw an exception
function unexpected() :never {
  throw Error('Unexpected');
}

function test(x: boolean) :number {
  if (x) {
    return 1;
  }
  unexpected(); // Since never represents a type that never occurs, number is not required as a return value
}

// The official documentation gives an example of an infinite loop
function infiniteLoop() :never {
  while (true) {}}Copy the code

5. Index signature

interface A {
  x: number
}
const a: A = {x: 1}

// The interface key type is string and the value type is Boolean
interface B {
  [key: string] :boolean
}
const b: B = {
  a: true.b: false
}

// in indicates traversal. The key names include 'a', 'b', and 'c'. The value type is string
type C = {
  [key in 'a' | 'b' | 'c'] :string
}
const c: C = {
  a: '1'.b: '2'.c: '3'
}
Copy the code

6. Access the type by index

(Official document)

interface A {
  a: string
  b: {
    c: boolean}}type Aa = A['a'] / / type string
type Abc = A['b'] ['c'] / / a Boolean type
Copy the code
// Extract the type corresponding to the primitive
type B = [string.number]
type B0 = B[0] / / type string
type B1 = B[1] / / number type
Copy the code
// Extract the element type of the array
type C = Array<string | number | boolean>

// Get the array element type by accessing any index of the array type
type D = C[0] / / type (string | number | Boolean)
Copy the code

7. Useas

The as keyword can be used to specify the type of the value, which can easily handle some ambiguous scenarios

function foo(str? :string) {
  return str.toString();
}

const obj = {
  toString() {
  }
}
foo(obj as string)
Copy the code

8. Condition types

As the name implies, a conditional type determines which type to use based on a condition (official document). The condition type looks something like this: T extends U? X : Y

// If T is of type string, return string, otherwise return number
type F<T> = T extends string ? string : number

const a: F<string> = 'abc'; // If the type of the generic is string, it is string
const b: F<number> = 1; // The generic type is of type number if it is not string
const c: F<boolean> = 2; // The generic type is of type number if it is not string
Copy the code

Use 9.is

The keyword is used for type protection

// Returns type Boolean, and tells the compiler to return true if value is of type string
function isString(value: any) :value is string {
  return typeof value === 'string';
}

function fn(val: number | string) {
  if (isString(val)) { // If this is true, val is of type string
    val.trim();
  } else { // Otherwise, val is number
    val.toFixed(2); }}Copy the code

The official array. isArray method definition uses the is keyword:

interface ArrayConstructor {
  isArray: (arg: any) = > arg is any[];
}
Copy the code

10. Define class attributes by modifying constructor parameters

Constructor parameters can be modified to quickly define class attributes and automatically assign values, as shown in the following example:

class Point {
  constructor(private x: number.private y: number){}}Copy the code
class Point {
  private x: number
  private y: number
  
  constructor(x: number, y: number) {
    this.x = x;
    this.y = y; }}Copy the code

The above two methods are equivalent, but the above one can write less code. In addition to modifying constructor parameters with private, other similar modifying keywords are public, protected, and readonly, as described in the official documentation

Second, generic

Generics can provide more flexible type constraints than being limited to one type. Commonly used in function, class, interface, type (official documentation)

1. Example

function

function foo<T> (arg: T) :T {
  return arg;
}
Copy the code

class

class Foo<T> {
  name: T

  constructor(name: T) {
    this.name = name;
  }

  getName(): T {
    return this.name
  }
}

const foo = new Foo<number> (3);
const name: number = foo.getName();
Copy the code

interface

interface Foo<T> {
  a: T
}

const foo: Foo<number> = { a: 1 }
Copy the code

type

type Foo<T> = { a: T }
const foo: Foo<boolean> = { a: false }
Copy the code

2. Generic constraints

Generics can be constrained by the extends keyword

/ / specify the type of the generic limited to: string | number, other types will be an error
interface A<T extends string | number> {
  [key: string]: T
}

const a: A<string> = {a: 'abc'}
const b: A<number> = {a: 123}
Copy the code

3. Specify the generic default type

interface B<T = number> {
  [key: string]: T
}

const c: B = { a: 123 }
const d: B<string> = { a: 'abc' }
Copy the code

Some TypeScript operators

Here’s a look at some of the TypeScript operators to help you understand what follows

  • ?: Indicates an optional parameter or attribute. It can be used for function parameters or interface attributes
  • -?: Deselect optional flags (extension: similar-readonlyCancels the readonly flag)
  • in: indicates the traversal type
  • typeof: Captures variable types, as shown above
  • keyof: A collection of strings or numbers that generate the keys of an object type, often withinUse a combination of
  • infer: indicates inferred types. The TS built-in types are described belowParametersThere will be concrete examples when you implement it

Implement TypeScript built-in types

TypeScript provides some common types that developers can use directly. Here’s how these types are implemented (built-in types use documentation)

1. Record

Construct a key-value pair type with key K and value T

/ / keyof any include: string | number | symbol
type Record<K extends keyof any, T> = {
  / / said key type is constrained in K (string | number | symbol) of one or more of the value type for T
  // in indicates traversal
  [P in K]: T
}

const foo: Record<string.boolean> = {
  a: true
}
const bar: Record<'x' | 'y'.number> = {
  x: 1.y: 2
}
Copy the code

2. Partial

Makes all attributes in T optional

type Partial<T> = {
  // Add all attributes of primitive type T to? Embellish, make optional
  [P inkeyof T]? : T[P] }interface Foo {
  a: string
  b: number
}

const foo: Partial<Foo> = {
  b: 2 // 'a' is no longer necessary
}
Copy the code

3. Required

In contrast to Partial, make all attributes in T required

type Required<T> = {
  // Add -? To all attributes of primitive type T. Embellish, become necessary
  / / -? Student: Move out? This logo
  [P inkeyof T]-? : T[P] }interface Foo {
  a: stringb? :number
}

const foo: Required<Foo> = {
  a: 'abc'.b: 2 // 'b' has become mandatory
}
Copy the code

4. Readonly

Make all properties in T read only

type Readonly<T> = {
  // Add the readonly modifier to all attributes of the primitive type T, making the attributes read-only
  readonly [P in keyof T]: T[P]
}

interface Foo {
  a: string
}

const foo: Readonly<Foo> = {
  a: 'abc'
}
// foo.a = 'def' // Read-only and unmodifiable


// In addition, you can use the -readonly modifier to remove the readonly modifier
type Writable<T> = {
  -readonly [P in keyof T]: T[P]
}

interface Bar {
  readonly a: string
}

const bar: Writable<Bar> = {
  a: 'abc'
}
bar.a = 'def'; // 'Bar['a'] has readonly modifier removed

Copy the code

5. Pick

Select properties from type T that come from set K

type Pick<T, K extends keyof T> = {
  [P in K]: T[P]
}

interface Foo {
  a: string
  b: number
  c: boolean
}

const foo: Pick<Foo, 'b' | 'c'> = {
  b: 1.c: false
}
Copy the code

6. Exclude

Exclude types from T that can be assigned to U

// If T is a subtype of U, return never, otherwise return T
type Exclude<T, U> = T extends U ? never : T

/ / 'a' | 'b' | 'c' exclude list 'b', only 'a' or 'c'
let foo: Exclude<'a' | 'b' | 'c'.'b'> = 'a'
foo = 'c'
Copy the code

7. Extract

In contrast to Exclude, extract the type T can assign to U

// Return T if T is a subtype of U, otherwise return never
type Extract<T, U> = T extends U ? T : never

/ / 'a' | 'b' | 'c' extract 'b', only for the 'b'
let foo: Extract<'a' | 'b' | 'c'.'b'> = 'b'
Copy the code

8. Omit

I’m going to omit some of the properties in T that come from the set K

// 1. Remove K from T attributes to get the rest of the set of attributes
// 2. Select the remaining set from T
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>

interface Foo {
  a: string
  b: number
  c: boolean
}

// Omit 'c' from Foo, leaving Foo with 'a' and 'b'
let foo: Omit<Foo, 'c'> = {
  a: 'a'.b: 1
}
Copy the code

9. NonNullable

Exclude null and undefined types

/ / exclude null | is undefined
type NonNullable<T> = T extends null | undefined ? never : T

type Foo = string | null
const a: NonNullable<Foo> = 'a' // Cannot be assigned to null or undefined
Copy the code

10. Parameters

Returns the corresponding tuple type based on the function’s arguments

Infer P is used to indicate function parameters to be inferred
type Parameters<T extends(... args:any) = >any> = T extends(... args: infer P) =>any ? P : never

type Foo = (a: string, b: number) = > void
const a: Parameters<Foo> = ['a'.1] // tuple [string, number]
Copy the code

11. ConstructorParameters

Returns the corresponding tuple type based on the constructor’s arguments

// Similar to Parameters
type ConstructorParameters<T extends new(... args:any) = >any> = T extends new(... args: infer P) =>any ? P : never

interface Foo {
  new(a: string.b: number)}const a: ConstructorParameters<Foo> = ['a'.1] // tuple [string, number]
Copy the code

12. ReturnType

Returns the return type of the function

// Similar to Parameters
type ReturnType<T extends(... args:any) = >any> = T extends(... args:any) => infer R ? R : any

type Foo = () = > boolean
const a: ReturnType<Foo> = true // Return Boolean
Copy the code

13. InstanceType

// Similar to Parameters
type InstanceType<T extends new(... args:any) = >any> = T extends new(... args:any) => infer R ? R : any
Copy the code

Refer to the link

  • TypeScript manual reference
  • Understand TypeScript in depth
  • A brief description of built-in types in TS