TS Everest 001 [Study Notes]

Course Outline: Set up a TypeScript development environment. Master TypeScript's basic, union, and intersection types. Understand the purpose and usage of type assertions in detail. Master type declaration methods for functions and classes in TypeScript. Master the purpose and definition of type aliases and interfaces. Master the application scenarios of generics and apply them proficiently. Flexibly apply conditional types, mapped types, and built-in types. Create and use custom types. Understand the concepts of namespaces and modules, and how to use...

Course Outline

  • Set up the TypeScript development environment.
  • Master TypeScript's basic types, union types, and intersection types.
  • Detail the purpose and usage of type assertions.
  • Master type declaration methods for functions and classes in TypeScript.
  • Master the purpose and definition of type aliases and interfaces.
  • Master generic application scenarios and skillfully apply generics.
  • Flexibly use conditional types, mapped types, and built-in types.
  • Create and use custom types.
  • Understand the concepts and usage scenarios of namespaces and modules.
  • Detail type guards and decorators in TS.
  • Cleverly use type inference and simplify code.
  • Deeply understand the TypeScript type hierarchy system.
  • Detail function variance and contravariance.
  • In-depth study of `infer` usage and techniques.
  • Detailed exploration of symbol types.
  • Flexibly write and use type declaration files to extend TypeScript's type system.
  • Master TS type file lookup rules.
  • Profoundly use decorators, leverage reflection metadata to extend decorator functionality, and achieve Inversion of Control (IoC) and Dependency Injection (DI).
  • In-depth analysis of the TSConfig configuration file.
  • TS Type Challenges

TS Basics

Currently, most medium to large front-end projects in enterprises use TypeScript, so why do we need it?

The core characteristic of JavaScript is its flexibility, but as project scale increases, this flexibility can actually add to the developer's cognitive load. For example, a variable in code can be assigned a string, boolean, number, or even a function, which introduces a lot of uncertainty. Furthermore, these uncertainties might only be discovered at runtime, which is why we need type constraints.

Of course, it's undeniable that the addition of types might somewhat affect development efficiency, but it can make large projects more robust.

  • TypeScript is more like backend Java, enabling JS to develop large enterprise applications;
  • The type system provided by TS can help us with rich syntax hints when writing code;
  • It performs type checking on code during development, thereby avoiding many online errors;

More and more projects are embracing TS, typically Vue3, Pinia, third-party utility libraries, backend NodeJS, etc. We also often write .d.ts files to provide better support for the above programming.

1. TS is a language

  1. TS is a superset of JS, extending its syntax by adding static type support and other new features.

Environment Configuration

Global installation

npm install typescript -g
# 我们可以用tsc来把ts转成js
# 我们要把什么转换成什么,所以我们要先生成一个配置
# 在当前项目下创建一个配置文件tsc --init
# --watch
tsc --init
# 插件code runner这个插件 需要额外安装一个ts-node的包
 npm init -y
 npm install typescript rollup -D
 npm install rollup-plugin-typescript -D
 npm i @rollup/plugin-node-resolve rollup-plugin-serve -D
#  rollup.config.js
# error lens 插件

Learning TS means learning types. TS type categories (DOM, Promise, primitive methods) are basic types.
In TS: what comes after the colon is a type = what comes after the equals sign is a value.
TS always prioritizes safety; whether an assignment is allowed depends on whether it's safe.
TS also has automatic type inference; you don't need to write types for every variable. You only need to write them yourself if the inference is incorrect.

Basic Types

let abc: string = 'Hello World';
console.log(abc);

let name = 'John Doe'; // 当前模块中,作用域隔离
let age = 20;
let handsome: boolean = true;
// 原始类似标识都是小写的,而类名都是大写的它描述的实例(都是对象)
// 类型注解:告诉TS变量的类型
// 类型推断:TS会自动尝试分析变量的类型
// 类型注解优先级高于类型推断
// 类型注解:变量名: 类型 = 值
// 类型推断:变量名 = 值
let s1: string = 'Hello World';
let s2: String = new String('Hello World');
let s3: String = 'Hello World'; // 会自动转换为对象
// 数组声明
let arr1: number[] = [1, 2, 3];
let arr2: Array<number> = [1, 2, 3];
// 元组:固定长度的数组
let tuple: [string, number] = ['Hello', 123];
// 元组的越界问题
// tuple[2] = 'World'; // 会报错
let tuple2: readonly [string, number, boolean] = ['Hello', 123, true];
// tuple2[0] = 'World'; // 会报错
export { name };

Enums (Objects with built-in types)

let abc: string = 'Hello World';
console.log(abc);

let name = 'John Doe'; // 当前模块中,作用域隔离
let age = 20;
let handsome: boolean = true;
// 原始类似标识都是小写的,而类名都是大写的它描述的实例(都是对象)
// 类型注解:告诉TS变量的类型
// 类型推断:TS会自动尝试分析变量的类型
// 类型注解优先级高于类型推断
// 类型注解:变量名: 类型 = 值
// 类型推断:变量名 = 值
let s1: string = 'Hello World';
let s2: String = new String('Hello World');
let s3: String = 'Hello World'; // 会自动转换为对象
// 数组声明
let arr1: number[] = [1, 2, 3];
let arr2: Array<number> = [1, 2, 3];
// 元组:固定长度的数组
let tuple: [string, number] = ['Hello', 123];
// 元组的越界问题
// tuple[2] = 'World'; // 会报错
let tuple2: readonly [string, number, boolean] = ['Hello', 123, true];
// tuple2[0] = 'World'; // 会报错

// 枚举 自带类型的对象,自动增长
enum USER_ROLE {
  USER,
  ADMIN = 6,
  MANAGER,
  OTHER = 'other', // 异构枚举
}
/*
  USER = 0,
  ADMIN = 6,
  MANAGER = 7,
*/
console.log(USER_ROLE.USER); // 0
// 如果不需要对象可以直接采用常量枚举
const enum USER_ROLE2 {
  USER,
  ADMIN,
  MANAGER,
}
console.log(USER_ROLE2.USER); // 0
export { name };

null and undefined

// 严格模式下,不允许使用 any 类型
// nul 和 undefined 是任何类型的子类型
let x: number | null | undefined = 1;
// let y: number = undefined; // 会报错
// let z: number = null; // 会报错
// strict:false 可以使用 any 类型

never type

Never

// never 类型 它是任何类型的子类型,也可以赋值给任何类型
// never 类型的变量只能被赋值为 never 类型
function fn1(): never {
  throw new Error('报错了');
}
// 类型保护,保障程序的不缺失
// never 是永远到达不了的终点
function fn2(): never {
  while (true) {}
}
function validate(x: never) {
  console.log(x);
}
// 针对不同的类型做不同的处理
function fn3(x: number | string | boolean) {
  // 类似有收敛的作用
  if (typeof x === 'number') {
    console.log(x.toFixed(2));
    return;
  }
  if (typeof x === 'string') {
    console.log(x.trim());
    return;
  }
  if (typeof x === 'boolean') {
    console.log(x.valueOf());
    return;
  }
  //守卫语句
  validate(x); // 如果类型不匹配,会报错 这个逻辑应该是永远不会执行的所以上在还是有没覆盖到的逻辑(要添加boolean类型的判断)
}

object type

// object 类型 object {} Object
let obj: object = { name: 'John Doe' };
// obj.name = 'Jane Doe'; // 会报错
// 小写的 object 是对象类型,大写的 Object 是对象的构造函数 

! non-null assertion operator

Union Types

// 一般我们会基于额外的类型来扩展定义类型 有点类似枚举
type Direction = "up" | "down" | "right" | "left"
let direction :Direction = "left"
// type和interface的区别
type women =
  | {
      wealthy: true;
      waste: string;
    }
  | {
      wealthy: false;
      norality: string;
    };
// 是富人一定不是节俭的人,是节俭的人一定不是富人

Union types can be used to achieve mutual exclusivity between properties.

Assertions

Assertions might lead to issues; proceed at your own risk.

type women =
  | {
      wealthy: true;
      waste: string;
    }
  | {
      wealthy: false;
      norality: string;
    };
// 是富人一定不是节俭的人,是节俭的人一定不是富人(类比约定,不严谨)
// 断言 把某个类型断言为为已经存在的一种类型
let ele = document.getElementById('app');
ele!.innerHTML = 'Hello World'; // 绕过TS的类型检查 ele?.innerHTML = 'Hello World'; // 可选链 操作符(取值)
// false || true = true
// false && true = false
// null ?? 'Hello World' = 'Hello World' // 空值合并操作符
// as 类型断言 可以强制把某个类型断言为另外一个类型 as 类型
// 双重断言,我们可以把一个值断言成为 any 类型,然后再断言成为另外一个类型
// 类型断言不是类型转换,只是告诉TS编译器,这个值是什么类型
// 类型断言只在编译阶段起作用,不会影响真实的值

Functions

// 函数类型

// 函数声明 function定义 函数表达式
function sum(a: number, b: number): number {
  return a + b;
}
let sum2 = function (a: number, b: number): number {
  return a + b;
};
let sum3: (a: number, b: number) => number = function (a, b) {
  return a + b;
};
// 类型比较长可以写成下面
type Sum = (a: number, b: number) => number;
let sum4: Sum = function (a, b) {
  return a + b;
};
// 会根据上下文推导赋予值的类型
let sum5: Sum = (a, b) => a + b;

// 常见的类型推导的方式
// 从右向左 根据赋值进行推导
let name = "jianz"
let age = 20
// 根据返回值进行类型推导
// void 表示不关心返回的具体类型(不校验)
// 可选参数(?)
let sum6 = (a: string = 'a', b?: string): string => {
  return a + b;
}; 

// 对象类型
let person = {
  name: 'John Doe',
  age: 20,
};
// ts中的this类型需要手动指定,默认是函数的第一个参数
function getVal(this: typeof person, key: keyof typeof person) {
  return this[key]; // this指向调用者,必须要有类型断言才能使用{
}
let r = getVal.call(person, 'name');
console.log(r);

Overloading

// 重载 (一般是有限操作), 它只是一个伪重载,只是一个类型的重载
function toArray(value: number): number[];
function toArray(value: string): string[];
function toArray(value: number | string) {
  if (typeof value === 'string') {
    return value.split('');
  } else {
    return value
      .toString()
      .split('')
      .map((item) => parseInt(item));
  }
}
let ar = toArray(123);
console.log(ar);
let ar1 = toArray('123');
console.log(ar1);

Classes (Can act as types themselves)

It can describe instances (class types).

// 类
class Circle {
  // 类的属性 ts中所有的属性都要先声明再使用
  PI = 3.14;
  // 类的构造函数
  constructor(public radius: number) {
    this.radius = radius;
  }
  // 类的方法
  area() {
    return this.PI * this.radius ** 2;
  }
}
// 还有一种写法
class Animals {
  constructor(public name: string) {
    // this.name = name; // 赋值也可以省去
  }
  eat() {
    console.log(this.name + ' is eating');
  }
}
const a1 = new Animals('dog');
a1.eat();
// 访问修饰
// public 公共的 默认的
// private 私有的 只能在类的内部访问
// protected 受保护的 只能在类的内部和子类中访问
// readonly 只读的 初始化之后不能修改
// static 静态的
// abstract 抽象的

// #号开头的属性是私有属性 只能在类的内部访问 不能在类的外部访问(这个是一个js语法)
// 不能new
class Singleton {
  private static instance: Singleton;
  private constructor() {}
  static getInstance() {
    if (!this.instance) {
      this.instance = new Singleton();
    }
    return this.instance;
  }
}
let sg1 = Singleton.getInstance();
// 抽象类不能new
// 不能实例化,只能被继承
// 抽象类中可以拥有具体宾实现
abstract class Animal {
  constructor(public name: string) {}
  abstract eat(): void; // 原型上的方法 默认采用这种方法更好些
  abstract play:()=>void; // 实例上的方法 ts中不做区分,但是一般的是实例方法
}

Interfaces

Interfaces can be understood as an abstraction of behavior (without concrete implementation), and can be used to describe objects, functions, classes, and mixed types.

// 接口是对行为的抽象,而抽象类是对类的抽象
// 用接口描述函数
// interface 描述的是形状或结构
interface IFullname {
  firstname: string;
  lastname: string;
}
type IFn = (obj: IFullname) => string;
let fn: IFn = ({ firstname, lastname }: IFullname): string => {
  return firstname + lastname;
};
fn({ firstname: 'John', lastname: 'Doe' });
// 1. 如果只是用来描述结构我们采用interface
// 2. 如果涉及到联合类型,则只能使用type
// 3. type不能扩展,interface可以扩展
// 4. type不能重名,interface可以重名
// 5. type可以使用typeof获取实例的类型,interface不行
// 6. type可以使用keyof获取key的类型,interface不行
// 7. type可以使用infer获取函数返回值的类型,interface不行
// 8. type可以使用extends实现交叉类型,interface不行
// 9. type可以使用条件类型,interface不行
// 10. type可以使用映射类型,interface不行
// 11. type可以使用索引访问操作符,interface不行

// 可以用接口描述混合类型
interface IFn1{
  (a:number,b:number):number;
  prop1:string;
  prop2:number;
}
// let fn11:IFn1 = (a,b)=>a+b; // 这样就报错了,因为fn11没有prop1和prop2属性且let定义可以重新被赋值
const fn11:IFn1 = (a,b)=>a+b;
fn11.prop1 = 'Hello';
fn11.prop2 = 123;
// 一般情况下我们使用interface来描述对象,如果需要使用联合类型,交叉类型,元组,只能使用type
interface IVeg {
  readonly color: string;
  size: number;
  taste?: 'sweet' | 'sour' | 'bitter'; // 可选属性
}
let veg: IVeg = {
  color: 'red',
  size: 20,
};
// veg.color = 'green'; // 会报错

If an object has more properties than defined by the interface,

  1. You can use assertions for assignment.
  2. You can write an interface with the same name based on interface characteristics.
  3. Create a new type by inheriting existing properties.
  4. Type compatibility.
  5. [key:string]:any for arbitrary type extension.
interface ICar {
  color: string;
  a: 1;
  b: 2;
}
type ValueOf = ICar[keyof ICar]; // 1 | 2 | string

主题测试文章,只做测试使用。发布者:Walker,转转请注明出处:https://walker-learn.xyz/archives/4409

(0)
Walker的头像Walker
上一篇 Mar 8, 2025 02:11
下一篇 Mar 27, 2025 15:01

Related Posts

  • In-depth Understanding of ES6 003 [Study Notes]

    Function parameter default values, as well as some details about the `arguments` object, how to use expressions as parameters, and the temporal dead zone for parameters. Previously, setting default values always relied on expressions containing the logical OR operator. When the preceding value was false, the latter value would always be returned. However, this became problematic if we passed 0 as an argument, requiring type verification. For example, `function makeRequest(url,timeout,callback){ timeout = t...`

    Personal Mar 8, 2025
    1.2K00
  • In-depth Understanding of ES6 001 [Study Notes]

    Block-Level Scope Binding
    Previously, `var` variable declarations, regardless of where they were declared, were considered to be declared at the top of their scope. Since functions are first-class citizens, the typical order was `function functionName()`, followed by `var variable`.

    Block-Level Declarations
    Block-level declarations are used to declare variables that cannot be accessed outside the scope of a specified block. Block-level scope exists in:
    - Inside functions
    - Within blocks (the region between `{` and `}`)

    Temporal Dead Zone
    When the JavaScript engine scans code and finds variable declarations, it either hoists them to the top of the scope...

    Personal Mar 8, 2025
    1.6K00
  • Love sports, challenge limits, embrace nature.

    Passion. In this fast-paced era, we are surrounded by the pressures of work and life, often neglecting our body's needs. However, exercise is not just a way to keep fit; it's a lifestyle that allows us to unleash ourselves, challenge our limits, and dance with nature. Whether it's skiing, rock climbing, surfing, or running, cycling, yoga, every sport allows us to find our inner passion and feel the vibrancy of life. Sport is a self-challenge. Challenging limits is not exclusive to professional athletes; it's a goal that everyone who loves sports can pursue. It can...

    Personal Feb 26, 2025
    1.3K00
  • Go Engineer Comprehensive Course 009 [Study Notes]

    Other features: Personal Center, Favorites, Manage shipping addresses (add, delete, modify, query), Messages. Copy inventory_srv --> userop_srv. Query and replace all inventory. Elasticsearch Deep Dive Document. 1. What is Elasticsearch. Elasticsearch is a distributed, RESTful search and analytics engine built on Apache Lucene, capable of quickly…

    Personal Nov 25, 2025
    24100
  • In-depth Understanding of ES6 008 [Study Notes]

    Iterators (Iterator) and Generators (Generator) are new features indispensable for efficient data processing. You will also find iterators present in other language features: the new for-of loop, the spread operator (...), and even asynchronous programming can use iterators. An iterator is a special object that has proprietary interfaces specifically designed for the iteration process. All iterator objects have a next() method, and each call returns a result pair...

    Personal Mar 8, 2025
    1.1K00
EN
简体中文 繁體中文 English
欢迎🌹 Coding never stops, keep learning! 💡💻 光临🌹