https://typescript.p6p.net/typescript-tutorial/intro.html

Typescript 介绍

  • typescript 是 javascrIpt 的超集(superset)该语言是完全兼容javascript,同时在该基础上进行了关键特性的补充,使得代码更易维护、代码更加健壮

  • typescript 是什么:

    • 1. 所有的合法的 JavaScript 代码都是可以直接在 typescript 环境中运行

    • 2. typescript增加了静态类型系统,并且最终是会被编译为纯 JavaScript 代码(这一步是为了兼容浏览器/运行环境)

    • 3. 起源地来自于微软以及被微软团队所维护,在生态上基本所有的前端框架和库都逐渐从 javascript-base -> typescript-base

  • typescript 核心特点:

    • 1. 静态类型检查

      • javascript 本身是是一个动态类型语言,和python2是很类型的,对于很多东西是没有约束的

      • 这种静态类型检查的优势让开发者规避了前期代码书写时候带来的很多低级错误,尤其在多人协作的时候

    • 2. 代码可读性和提示增强

      • 在开发中明确了类型,编辑器可以给出更加精准的代码提示

    • 3. 对未来的 Javascript 兼容性增强

      • TS 会提前支持 ES6 + 甚至还未正式纳入标准的 JavaScript 新特性(比如装饰器、可选链等),编译时可以根据你的需求,将其转换成低版本的 JavaScript,兼顾 “新特性” 和 “兼容性”

    • 4.面向对象特性增强

      • TS 完善了 JavaScript 的面向对象能力,比如明确的类(Class)、接口(Interface)、泛型(Generic)、枚举(Enum)等,让复杂业务逻辑的代码结构更清晰

  • TypeScript 是 JavaScript 的超集,核心增加了静态类型系统,编译后仍为纯 JS;

  • 最大价值是提前发现类型错误、增强代码提示,适合大型 / 长期维护的前端项目;

  • 完全兼容 JS,学习成本低,是前端工程化的重要工具

Typescript 类型系统

基础类型

  • 基础类型就是对应的是 javascript 的基础数据类型的讷

TS 类型

说明

示例

number

数字(整数 / 浮点数 / NaN/Infinity)

let age: number = 20;

string

字符串

let name: string = "TS";

boolean

布尔值(仅 true/false)

let isOk: boolean = true;

null

空值(单独使用时意义小,常和其他类型结合)

let n: null = null;

undefined

未定义

let u: undefined = undefined;

symbol

唯一值(ES6 特性)

let s: symbol = Symbol("key");

bigint

大整数(ES6 特性)

let b: bigint = 100n;

void

无返回值(主要用于函数)

function fn(): void { console.log("hi"); }

never

永不存在的值(比如抛出错误 / 无限循环的函数返回值)

function error(): never { throw new Error("错了"); }

复合类型

  • 数组类型

// 数组类型的使用
/**
 * 对于typescript数组类型的使用方法是两种
 * 1. type[]
 * 2. Array<type>
 */
const arr: number[] = [1, 2, 3];
const arr01: Array<number> = [1, 2, 3];
  • 对象类型

// 对象类型的使用

// 1. 直接约束的使用,但是这种的类型的使用类型无法达到复用
let user: { name: string; age: number; gender?: string } = {
  name: "张三",
  age: 25
};

// 2. type 定义类型
type User = {
  name: string;
  age: number;
  gender?: string;
}
const user01: User = {
  name: "张三",
  age: 25,
  gender: "男"
}

// 3. interface 定义类型
interface User02 {
  name: string;
  age: number;
  gender?: string;
}
const user02: User02 = {
  name: "张三",
  age: 25,
  gender: "男"
}

/**
 * interface 和 type 区别
 * 1. interface 可以定义多个接口,type 只能定义一个类型
 * 2. interface 可以继承多个接口,type 只以继承一个类型
 * 3. interface 可以定义默认实现,type 不能定义默认实现
 * 4. interface 可以定义枚举类型,type 不能定义枚举类型
 */
  • 接口(interface)

// 定义接口
interface User {
  name: string;
  age: number;
  gender?: string; // 可选属性
  readonly id: number; // 只读属性
}

// 复用接口
let user1: User = { id: 1, name: "张三", age: 25 };
let user2: User = { id: 2, name: "李四", age: 30, gender: "男" };
  • 联合类型(|)

// 变量可以是数字 或 字符串
let numOrStr: number | string = 10;
numOrStr = "hello"; // 合法
numOrStr = true; // 报错(不是number/string)
  • 交叉类型(&)

interface A { a: number }
interface B { b: string }
// 变量必须同时有 a(数字)和 b(字符串)
let ab: A & B = { a: 1, b: "2" };
  • 枚举类型

// 数字枚举
enum Status {
  Success, // 0
  Error,   // 1
  Loading  // 2
}
let status: Status = Status.Success; // 等同于 status = 0

// 字符串枚举
enum Direction {
  Left = "LEFT",
  Right = "RIGHT"
}
let dir: Direction = Direction.Left; // 等同于 dir = "LEFT"
  • 泛型

// 定义泛型函数:T 是类型变量,调用时指定具体类型
function getValue<T>(value: T): T {
  return value;
}

// 调用时指定 T 为 number
let num = getValue<number>(10);
// 调用时指定 T 为 string
let str = getValue<string>("hello");

Typescript extend + infer

  • extends 的使用的话核心是 T extends U ? T : U 这就是基本的用法吧

    • 我们常用 extend 关键字来做对应的分布式的类型处理吧

// extend 关键字的使用

type IsNumber<T> = T extends number ? true : false;

// 开始进行使用吧
type A = IsNumber<123>;
type B = IsNumber<"str">;
type C = IsNumber<true>;

// 联合类型检查
type CheckUnion<T> = T extends number ? true : false;
type D = CheckUnion<number | string>;
  • infer 就是对于 extends 关键字的补充吧

type GetArrayItemType<T> = T extends Array<infer R> ? R : never;

type NumArray = number[];
type NumArrayItemType = GetArrayItemType<NumArray>;

type StrArray = string[];
type StrArrayItemType = GetArrayItemType<StrArray>;

type BoolArray = boolean[];
type BoolArrayItemType = GetArrayItemType<BoolArray>;
  • 综合使用

/**
 * typeof 和 keyof 在typescript 类型系统中的区别
 * typeof 用于获取类型的运行时值,而 keyof 用于获取类型的键名。
 */
// 通过 extends 和 infer 实现一些内置的类型工具

type MyReturnType<T> = 
  T extends (...args: Array<any>) 
    => infer R
      ? R
      : never

function add(a: number, b: number) {
  return a + b;
}
type AddFuncType = MyReturnType<typeof add>;
type MyParameters<T> = 
  T extends (...args: infer Args) => any
    ? Args
    : never

function add(a: number, b: number) {
  return a + b;
}
type AddFuncType = MyParameters<typeof add>;
// 解包 Promise 类型
type UnwrapPromise<T> = 
  T extends Promise<infer R> 
    ? R 
    : T;

// 使用
type PromiseNum = Promise<number>;
type Unwrapped1 = UnwrapPromise<PromiseNum>; // number

type PromiseStr = Promise<string>;
type Unwrapped2 = UnwrapPromise<PromiseStr>; // string

type NormalNum = number;
type Unwrapped3 = UnwrapPromise<NormalNum>; // number
// 递归解包嵌套 Promise
type DeepUnwrapPromise<T> = 
  T extends Promise<infer R> 
    ? DeepUnwrapPromise<R> // 递归解包内层
    : T;

// 使用
type NestedPromise = Promise<Promise<Promise<string>>>;
type Unwrapped = DeepUnwrapPromise<NestedPromise>;
// 提取对象 T 中属性 K 的类型
type GetPropType<T, K extends keyof T> = 
  T extends { [key in K]: infer R } 
    ? R 
    : never;

// 使用
interface User {
  name: string;
  age: number;
  address: { city: string };
}
// 提取 name 属性的类型:string
type NameType = GetPropType<User, "name">;
// 提取 address 属性的类型:{ city: string }
type AddressType = GetPropType<User, "address">;
// 提取 address.city 的类型:string
type CityType = GetPropType<AddressType, "city">;

Typescript 类型工具

https://typescript.p6p.net/typescript-tutorial/utility.html