10
头图

Hello, brave friends, hello everyone, I am your little five, the king of the mouth, I am in good health, and my brain is not sick.

I have a wealth of hair loss skills, which can make you a veteran celebrity.

It is my main theme that I will write it when I read it, and it is my characteristic to pick my feet. There is a trace of strength in the humble, and the stupid blessing of a fool is the greatest comfort to me.

Welcome to fifth of essay series the typescript study notes.

Guide

The original intention of this article is for the author TS for a period of time. The content of the article is relatively basic, suitable for learning as an entry-level tutorial; and the coverage is not comprehensive, and it lacks many contents including classes. If you don't mind the above points, welcome to join the author on this rigorous but interesting fantasy journey.

Basic type

Boolean-Boolean

let flag: boolean = false;

Number-Number

let num: number = 10;

👺 Extension: The number type also supports binary (beginning with 0b) , octal (beginning with 0o) , hexadecimal (beginning with 0x) literals. It will be converted to the corresponding decimal number when it is converted to arithmetic or output.

let num02: number = 0b1010;
let num08: number = 0o744;
let num16: number = 0xf00d;

String-String

let str: string = '黄刀小五';

Array-Array

There are two ways to define an array: Array<T> or T[] (T is the element type of each item in the array)

let numArr: number[] = [1, 2, 3];
let numArr: Array<number> = [1, 2, 3];

Tuple-tuple

👺 Features: <array>, <known length>, <each element type is different>

😼 is an array that defines the data type for each item

let tuple: [string, string, number, boolean?] = ['No.1', '黄刀小五', 18];

🦥 Application:

  • UseState of React Hook
import { useState } from 'react';
const [loading, setLoading] = useState<boolean>(false); // 这里类型可省略, 详见后文类型推断
  • csv data format
type Touple = [string, number, string];
let csvData: Touple[] = [['黄刀小五', 18, '男'], ['二狗子', 14, '男']];

👺 Extension: Tuple out of bounds

let tuple: [number, string] = [1, '黄刀小五'];
tuple.push(2); // ✅ right 元组越界时, 该项类型相当于对元组的各项类型做联合

/* 过程如下, 看不懂的看官莫慌, 请先看后文 */
type UnionType<T> = T extends (infer P)[] ? P : never;
type TupleType = UnionType<typeof tuple>; // number | string

Enum-Enumeration

enum Active {
  inactive,
  active,
}

enum Fruit {
  apple = 'apple',
  orange = 'orange',
  banana = 'banana',
}

If the enumeration type does not specify a value or the specified value is a number type, such as the above Active , it can be bidirectionally selected: Active[0] , Active['active'] , and the mapping is as follows [👇]

{
  0: 'inactive',
  1: 'active',
  inactive: 0,
  active: 1,
}

One item of the enumeration can be assigned a value (usually the first item), and the remaining items will increase in order

enum Type {
  active = 1,
  inactive,
}

{ // 对应映射为
  1: 'active',
  2: 'inactive',
  active: 1,
  inactive: 2,
}

😼 tips: recommended to use the enumeration in the form of assignment. It is more readable, such as the above Fruit

🦥 Application:

  • combination with 160b8850d6a11b switch ... case :
enum ActionType {
  ADD = 'ADD',
  EDIT = 'EDIT',
  DELETE = 'DELETE',
}

const reducer = (type: ActionType) => {
  switch(type) {
    case ActionType.ADD:
      // xxx
      break
    case ActionType.EDIT:
      // xxx
      break
    ...
  }
}

reducer(ActionType.ADD); // ✅ right
let params = 'ADD';
reducer(params); // ❎ error (类型“string”的参数不能赋给类型“ActionType”的参数)

/* 😼 tips: 非赋值形式大家可自行尝试 */
  • Define type mapping or define a set of constants
enum Status { // 类型映射
  unprocessed = 1, // 未处理
  processed, // 已处理
  refused, // 已拒绝
}

enum Fruit { // 常量
  apple = '苹果',
  orange = '橘子',
  banana = '香蕉',
}

👺 Extension: keyof typeof Enum , can convert enumeration type to union type; trust me, you will use it😏

enum ActionType {
  ADD,
  EDIT,
  DELETE,
}
type ActionTypeConst = keyof typeof ActionType // 'ADD' | 'EDIT' | 'DELETE'

Any-any type

let value: any;

😼 tips: the top of the food chain, the use of any

Unknown-unknown type

let value: unknown;

Unknown represents an unknown type, and the any different is unable to Unknown perform any type of operation under careful consideration. < the any : any type>, < Unknown : unknown type> difference.

👉 Take number an toFixed() method:

  • unknown I don't know what type it is, but only number has toFixed() method, so it cannot be used;
  • And any represents that I can be of any type. At this time toFixed() method, which is number type;

😼 tips: If you want to use any , please consider whether unknown can be used instead. (With the following type protection, you can eat with peace of mind)

Void-no type

Often used for functions that have no specific return value

const fn = (str: string): void => {
  // 执行xxx事件
}

Null and Undefined

let u: undefined = undefined;
let n: null = null;

These two don't know what to say, just add the following two points (but it nothing to do TS 160b8850d6a3f8)

  1. Number(undefined) => NaN, Number(null) => 0
  2. const fn = (arg?: string) => { ... } Arg type is string | undefined

Never-never return

let n: never;
  • never represents those values that never exist. When we don't want to capture the current value, we can use never ;
  • No type can be assigned to never , including any ;
  • never | T = T This feature can be used to filter out unwanted values;

🦥 Application:

  • Type check
type Type = string | number;

const fn = (arg: Type) => {
  if (typeof arg === 'string') { ... }
  else if (typeof arg === 'number') { ... }
  else { const check: never = arg; }
}

As above, we will never else at this time, so let's do the following:

- type Type = string | number;
+ type Type = string | number | boolean;

* 此时 else 中的 check 会报错 (不能将类型“boolean”分配给类型“never”)

Type inference

If no type is specified, TS will infer a type based on type inference.

let val; // 推论成: let val: any;
let num = 10; // 推论成: let num: number = 10;
num = '黄刀小五'; // ❎ error (不能将类型“string”分配给类型“number”)

🦥 Application: <single static type-such as the above num>, <function return value-in general, the return value type can be correctly inferred, without additional specification> <child element in the loop>

😼 tips: If TS can correctly infer its type, we can use type inference without having to define the type.

Type assertion

Type assertions are used to tell the compiler "I know what I'm doing". There are angle brackets and as . In the $tsx$ syntax, only as is supported.

* 😼 tips: 下面我们使用数组来举个例子, 实际场景中应使用元组.

type Key = string | number;
let arr: Key[] = ['黄刀小五', 18];

// 不能将类型“Key”分配给类型“string”
- let name = arr[0];
- console.log(name.length);

// 使用类型断言
+ let name = arr[0] as string;
+ let name = <string>arr[0];
+ console.log(name.length);

Interface-Interface

Interface is used to define the type of object

interface User {
  readonly id: number; // 只读属性, 不可修改
  name: string; // 必须属性
  desc?: string; // 可选属性
  say?: (name: string) => void; // 方法
}

const say = (name: string) => { ... }
let user: User = {
  id: 1,
  name: '黄刀小五',
  say,
}

user.id = 2; // ❎ error (无法分配到 "id" ,因为它是只读属性)

index signature -make the interface more flexible

interface User {
  [key: string]: string; // 表示 key 为 string, value 为 string 的任意属性
}

let user:User = {
  name: '黄刀小五',
  desc: '菜鸡前端一只',
}

😼 tips: must meet the characteristics of the index signature, and the index signature parameter type must be string | number

interface User {
  [key: string]: string;
  age: number; // ❎ error (类型“number”的属性“age”不能赋给字符串索引类型“string”。)
}

interface merge

interface User {
  name: string;
}
interface User {
  age: number;
}
/* 两者会合并为👇 */
interface User {
  name: string;
  age: number;
}

interface inherits

Keywords: extends

interface Person {
  name: string;
}
interface User {
  age: number;
}
interface Student extends Person, User {
  desc: string;
}
/* Student接口格式如下👇 */
interface Student {
  name: string;
  age: number;
  desc: string;
}

😼 tips: interface when both the 160b8850d6a749 interface and type alias can be used

🤔 Thinking: How to define a tree structure

interface Tree {
  key: number;
  value: string;
  child?: Tree[];
}
let tree: Tree[] = [];

Type alias

As the name suggests, give the type a new name

type Key = string | number;

and Interface contrast

  • type does not support inheritance and declaration merging, interface can, please refer to the above;
  • type more general, the right side can be any type, interface mainly used to define objects;
  • type and interface can be used, use interface ;

Union type and cross type

  • Union type (A | B)
type Key = string | number; // 代表 string 或 number 类型

😼 tips: joint types can be used to declare specific values

type Status = 'active' | 'inactive';
  • Crossover type (A & B)
interface User {
  name: string;
}
interface Student {
  age: number;
}
type Blogger = User & Student;

/* Blogger类型格式如下👇 */
{
  name: string;
  age: number;
}

😼 tips: two basic types cross, will generate never type

type Key = string & number; // never, 没有类型可以满足即是 string 又是 number

Type lookup

Type search can extract the type of an attribute on the object type

interface Person {
  User: {
    name: string;
    age?: number;
  }
}
type User = Person['User']

😼 tips: often used in occasions where third-party library types cannot be referenced

Common keywords

const

👺 Use type assertion as to declare constants

type Status = 'active' | 'inactive';
const fn = (status: Status) => { ... }

- let status = 'active'; // 此时 'active' 被解析为字符串而非常量
- fn(status); // ❎ error (类型“string”的参数不能赋给类型“Status”的参数)

* 以下3种等价, 均可将 'active' 解析为常量
+ let status = 'active' as const;
+ const status = 'active';
+ let status: Status = 'active';
+ fn(status); // ✅ right

😼 tips: constants defined by third-party plugins often need to as const used with 060b8850d6a9d9

typeof

👺 Used to get the type of the variable

let str = '黄刀小五';
type Str = typeof str; // type Str = string

let user = { name: '黄刀小五' }
type User = typeof user; // type User = { name: string; }

keyof

key value used to extract the object type

interface User {
  name: string;
  age?: number;
}
type Key = keyof User; // type Key = 'name' | 'age'

Type protection

Why type protection is needed

const fn = (value: string | number) => {
  if (value.length) { ... } // ❎ error (类型“string | number”上不存在属性“length”)
}

The above code, what if you want to execute a piece of logic value: string

At this time, type protection is needed. After using type protection, the current code segment will be executed according to the type specified in advance.

👺 typeof

const fn = (value: string | number) => {
  if (typeof value === 'string') { // 利用 typeof 限制 value 的类型为 string
    console.log(value.length);
  }
}

👺 is

const isString = (x: unknown): x is string => {
  return typeof x === 'string';
}
const fn = (value: string | number) => {
  if (isString(value)) console.log(value.length); // value is string
}

👺 in

Indicates whether a property exists in the current object

interface User {
  name: string;
  age?: number;
}
const fn = (args: User) => {
  if ('age' in args) { ... }
  else { ... }
}

fn({ name: '黄刀小五', age: 18 }); // 执行 if 语句
fn({ name: '黄刀小五' }); // 执行 else 语句

Generic

👺 Function: Used for code reuse

Let's look at an example first

const fn = (value: number): number => value;

🤔 Thinking about What if I want to pass in a string type and return a string type at this time

const fn = <T>(value: T): T => value;
fn<string>('黄刀小五'); // const fn: <string>(value: string) => string

* 😼 tips: 可根据 类型推断 推断出其为 string 类型, 而不用特意指定 -> `fn('黄刀小五');`

Above, a generic is implemented, which can take the type as a parameter and pass in the type to specify when calling.

👺 Note: In $tsx$, <T> will be parsed into a label, you can use the following writing:

const fn = <T extends {}>(value: T): T => value; // extends也可用于缩小T的范围
const fn = <T,>(value: T): T => value;
  • Pass in multiple types:
const fn = <T, U>(type: T, value: U): U => { ... };
fn<boolean, string>(true, '黄刀小五');

The role of generics is quite broad, such as defining an interface:

interface Teacher<T> {
  readonly id: number;
  name: string;
  student?: T[];
}
interface Student {
  readonly id: number;
  name: string;
  age?: number;
}
let teahcer: Teacher<Student> = {
  id: 1,
  name: '黄刀小五',
  student: [{
    id: 1001,
    name: '二狗子',
    age: 14,
  }]
}

Commonly used syntactic sugar

Next, let's use the above knowledge to implement the syntax sugar TS (Reminder: It is recommended to understand the above first, at least understand the generics before reading the content below) look down 👇

Readonly

👺 Change the attributes of the object type to read-only

  • Code
type Readonly<T> = {
  readonly [K in keyof T]: T[K];
};
  • Demo
interface Person {
  readonly name: string;
  age: number;
  desc?: string;
}
let person: Readonly<Person> = {
  name: '黄刀小五',
  age: 18,
}
person.age = 19; // ❎ error (无法分配到 "age" ,因为它是只读属性)

Partial

👺 Change the attributes of the object type to optional

  • Code
type Partial<T> = {
  [K in keyof T]?: T[K];
};
  • Demo
interface Person {
  readonly name: string;
  age: number;
  desc?: string;
}
let person: Partial<Person> = {}; // 此时所有属性均为可选

Required

👺 Make all the attributes of the object type mandatory

  • Code
type Required<T> = {
  [K in keyof T]-?: T[K];
};

😼 Tips: ? - represents optionally removing symbols ? , this symbol ( - ) likewise be used in other positions, such as: -readonly removable read-only attributes.

  • Demo
interface Person {
  readonly name: string;
  age: number;
  desc?: string;
}
let person: Required<Person>> = {
  name: '黄刀小五',
  age: 18,
  desc: '基于搜索引擎的复制粘贴工程狮',
}; // 此时所有属性均为必须

Record

👺 Map all attribute values of one type to another type and create a new type

  • Code
type Record<K extends string, T> = {
  [P in K]: T;
};
  • Demo
interface Person {
  readonly name: string;
  age: number;
  desc?: string;
}
type Kind = 'teacher' | 'student';
let person: Record<Kind, Person> = {
  teacher: {
    name: '黄刀小五',
    age: 18,
  },
  student: {
    name: '二狗子',
    age: 14,
  }
}; // 将 Person 类型映射到 Kind 类型中

/* Record<Kind, Person> 相当于👇 */
type NewPerson = {
  [key in Kind]: Person
};

Extract

👺 from T extraction the U-

  • Code
type Extract<T, U> = T extends U ? T : never;
  • Demo
type Student = '二狗子' | '如花';
type Teacher = '黄刀小五' | '二狗子';
type Trainee = Extract<Student, Teacher>; // 输出 '二狗子'

/* Extract<Student, Teacher> 相当于👇 */
'二狗子' in Teacher -> '二狗子'
'如花' in Teacher -> never
'二狗子' | never = '二狗子'

Exclude

👺 from T excluded the U-

  • Code
type Exclude<T, U> = T extends U ? never : T;
  • Demo
type Student = '二狗子' | '如花';
type Teacher = '黄刀小五' | '二狗子';
type OnlyStudent = Exclude<Student, Teacher>; // 输出 '如花'

/* Exclude<Student, Teacher> 相当于👇 */
'二狗子' in Teacher -> never
'如花' in Teacher -> '如花'
'如花' | never = '如花'

Pick

👺 Select some attributes in the object

  • Code
type Pick<T, K extends keyof T> = {
  [P in K]: T[P];
}
  • Demo
interface Person {
  readonly name: string;
  age: number;
  desc?: string;
}
let person: Pick<Person, 'age' | 'desc'> = {
  age: 18,
};

/* Pick<Person, 'age' | 'desc'> 相当于👇 */
interface Person {
  age: number;
  desc?: string;
}

Omit

👺 Ignore some attributes in the object

  • Code
type Omit<T, K> = Pick<T, Exclude<keyof T, K>>;
  • Demo
interface Person {
  readonly name: string;
  age: number;
  desc?: string;
}
let person: Omit<Person, 'name'> = {
  age: 18,
};

/* Omit<Person, 'name'>相当于👇 */
interface Person {
  age: number;
  desc?: string;
}

ReturnType

👺 Get the return value type of the method

  • Code
type ReturnType<T> = T extends (
  ...args: any[]
) => infer R ? R : any;

-> infer with extends to infer the return value type of the function

  • Demo
const getName = (name: string) => name;
type ReturnGetName = ReturnType<typeof getName>; // string

Parameters

👺 Get the parameter type of the method

  • Code
type Parameters<T> = T extends (
  ...args: infer P
) => any ? P : never;

-> Here infer used to infer the parameter type of the function, and the Parameters is a tuple.

  • Demo
const getName = (name: string) => name;
type ParamGetName = Parameters<typeof getName>; // [name: string]

NonNullable

👺 Exclude null and undefined type

  • Code
type NonNullable<T> = T extends null | undefined ? never : T;
  • Demo
type NewPerson = Person | null;
let person: NonNullable<NewPerson> = null; // ❎ error (不能将类型“null”分配给类型“Person”)

Concluding remarks

Combined with the content of the article, you can package more syntactic sugar according to actual needs, which is convenient for use in the project. If you want to learn TS more detail, here is a blogger TS article, and a detailed explanation of a feature of TS

Reference 🔗 link

[TypeScript document]

[FESKY] Learning Typescript with examples

[Wayong Liu] TypeScript infer keyword


黄刀小五
305 声望22 粉丝

前端开发攻城狮, 擅长搬砖, 精通ctrl + c & ctrl + v, 日常bug缔造者.