TS-XM

57 阅读7分钟

01-any 利 unknown.ts

let a1: unknown = { a: 1 };
// a1.unknown  // "a1"的类型为"未知".ts(18046)

let a2: any = { a: 1 };
console.log(a2.a); // 1

// unknown 比 any 安全

02-object 相关加餐.ts

// Object 类似于 any,表示允许对象,
let a: Object = {};
let a1: Object = 123;
let a2: Object = "123";

//   小写的才是对象包含 数组 对象 函数
let a12: object = { name: "123" };
let a13: object = [];
let a14: object = () => {};

//   {} 类似于 any,表示允许对象,
let a15: {} = "";
let a16: {} = 123;
let a17: {} = { name: "123" };

let a18: {} = { name: "123" };
//   a18.age = 123; // 类型"{}"上不存在属性"age".ts(2339)

03-interface.ts

interface person {
  name: string;
  age: number;

  // 这样写 就可以在下面加任何属性了,不在校验
  [key: string]: any;
}
var p: person = { name: "John", age: 30 };
//   1. 不能多也不能少
//   var p2: person = { name: "John", age: 30, };
//   var p3: person = { name: "John" };

//   2. ? 号就是可有可无
interface a1 {
  a2?: string;
}
let a3: a1 = { a2: "123" };
let a4: a1 = {};

// 3. 只读属性
interface a5 {
  readonly a6: () => boolean;
}
let a7: a5 = {
  a6: () => false,
};
//   a7.a6 = () => {}; // 无法为"a6"赋值,因为它是只读属性.

// 4. 继承
interface a8 extends a5 {
  a9: string;
}
let a10: a8 = {
  a6: () => false,
  a9: "123",
};

// 5. 定义函数
interface Fn {
  (name: string): number[];
}
const fn: Fn = (name: string) => [1, 2, 3];

04-数组.ts

// 两种方式
//   1. 定义普通类型
let a1: number[] = [1];
let a2: Array<boolean> = [false];

//   2. 定义对象数组 使用 interface
interface a3 {
  name: string;
}
const a4: a3[] = [{ name: "a4" }];

//   3. 定义二维数组
let a5: number[][][] = [[[1]]];
let a6: Array<Array<number>> = [[2]];
let a7: any[] = [1, "2"];
let a8: [string, number] = ["1", 2];

//   4. 参数数组
function a9(...arg: string[]) {
  // {
  //     "0": "123"
  // }
  console.log(arguments);
  let a10: IArguments = arguments;
  console.log(a10);
  // {
  //     "0": "123"
  // }

  console.log(arg); // ['123']
}
a9("123");

05-函数扩展.ts

// 1. 定义参数和返回值
function a1(a: number, b: number): number {
  return a + b;
}
console.log(a1(1, 32)); // 33
const a2 = (a: number, b: number): number => {
  return a + b;
};
console.log(a2(1, 32)); // 33

//   2. 默认参数 和 参数可选 ?
function a3(a?: number, b: number = 10): number {
  return a + b;
}
console.log(a3(1, 32)); // 32
console.log(a3(1)); // 11
console.log(a3()); // NaN

//   3. 传递一个对象参数
interface a4 {
  name?: string;
  age?: number;
}
function a5(a: a4): a4 {
  return a;
}
console.log(a5({ name: "xiaoming", age: 18 })); // {name: "xiaoming", age: 18}

//   4. this类型
interface a6 {
  user: number[];
  add: (this: a6, num: number) => void;
}
let a7: a6 = {
  user: [1, 2, 3],
  add: function (this: a6, num: number) {
    this.user.push(num);
    console.log(this.user); // [1, 2, 3, 4]
  },
};
a7.add(4);
console.log(a7.user); // (4) [1, 2, 3, 4]

//   5. 函数重载 一个函数实现多个功能
let a8: number[] = [1, 2, 3];
function a9(add: number[]): number[]; // 如果是一个number数组那就添加
function a9(add: number): number[]; // 传入单个id就查询
function a9(): number[]; // 没有传东西就查询所以
function a9(ids?: number | number[]): number[] {
  // 可选 ids 所以要加?
  if (typeof ids === "number") {
    return a8.filter((item) => item === ids);
  } else if (Array.isArray(ids)) {
    a8.push(...ids);
    return a8;
  } else {
    return a8;
  }
}
console.log(a9(1)); // [1]
console.log(a9([1, 2, 3])); //  [1, 2, 3, 1, 2, 3]
console.log(a9()); // [1, 2, 3, 1, 2, 3]

06-类型断言,联合类型,交叉类型.ts

// 1. 联合类型
let a1: number | string = "10";
let a2 = function (type: number): boolean {
  return !!type;
};
let a3 = function (type: number | boolean): boolean {
  return !!type;
};
console.log(a3(2)); // true
console.log(a3(false)); // false

//   2. 交叉类型
interface a4 {
  name: string;
  age: number;
}
interface a5 {
  sex: string;
}
const a6 = (man: a4 & a5): void => {
  console.log(man);
};
a6({
  name: "123",
  age: 12,
  sex: "男",
});
//   {
//     "name": "123",
//     "age": 12,
//     "sex": "男"
// }

//   3. 类型断言(欺骗ts)
function a7(num: number | string): void {
  console.log((num as string).length);
}
a7(123); // undefined
a7("123"); // 3

interface a8 {
  name: string;
}
interface a9 {
  age: number;
}

let a10 = (type: a8 | a9): void => {
  // 断言的写法
  console.log((<a9>type).age);
  console.log((type as a9).age);
};
a10({ name: "123" }); // undefined
a10({ name: "123", age: 12 }); // 12

const a11 = (type: any): boolean => {
  return type as boolean;
};
console.log(a11("123"));

07-内置对象.ts

let num: Number = new Number(1);
let date: Date = new Date();
let regExp: RegExp = /^[0-9]+$/;
let error: Error = new Error("Error");
let xhr: XMLHttpRequest = new XMLHttpRequest();

let div: HTMLDivElement = document.createElement("div");
let input: HTMLInputElement = document.createElement("input");
let div1: NodeList = document.querySelectorAll("div");
let div2: NodeListOf<HTMLDivElement> = document.querySelectorAll("div");

let arr: Array<string> = ["1", "2", "3"];

08-class.ts

interface a1 {
  name: string;
  value: number;
}
interface a2 {
  options: a1;
  init(): void;
}
interface Vnode {}
class a3 implements a2 {
  options: a1;
  constructor(options: a1) {
    this.options = options;
  }
  init(): void {
    let data: Vnode = {};
    console.log(1);
  }
}
const a4 = new a3({ name: "a", value: 1 });
//   a4.init(); // 1   属性"init"为私有属性,只能在类"a3"中访问.

//   2. class 修饰符

09-抽象类.ts

abstract class a1 {
  name: string;
  constructor(name: string) {
    this.name = name;
  }
  getName(): string {
    return this.name;
  }
  // abstract 只能描述不能实现
  abstract init(name: string): void;
}
//   const a2 = new a1()   // 无法创建抽象类的实例.

//   继承的时候 需要定义这个方法了
class a3 extends a1 {
  init(name: string) {
    console.log(name);
  }
}
const a4 = new a3("987");
console.log(a4.getName());

a4.init("123");

10-元组类型.ts

// let a: readonly [x: number, y: boolean] = [1];  // 不能将类型"[number]"分配给类型"readonly [x: number, y: boolean]".
let a: readonly [x: number, y?: boolean] = [1, false]; // 不能将类型"[number]"分配给类型"readonly [x: number, y: boolean]".

// a[0] = 2;
// a.push(null);
// a.push("12"); // 类型""12""的参数不能赋给类型"number | boolean"的参数.
console.log(a);

type first = (typeof a)["length"];
const a2: first = 1;
const a3: first = 2;
// const a4: first = 3;  // 不能将类型"3"分配给类型"1 | 2".ts(2322)

11-枚举类型.ts

enum a1 {
  red,
  green,
  black,
}
console.log(a1.red); // 0

//   2. 增长枚举
enum a2 {
  red = 1,
  green,
  black,
}
console.log(a2.green); // 2

//   3. 字符串枚举
enum a3 {
  red = "red",
  green = "green",
  black = "black",
}
console.log(a3.green); // green

//   4. 异构枚举
enum a4 {
  yes = 1,
  // gooft = "aa",   // 枚举成员必须具有初始化表达式.ts(1061)
  goof,
  no = "no",
}
console.log(a4.no); // no
console.log(a4.goof); // 2

//   5. 接口枚举
interface a5 {
  red: a4.yes;
}
let a6: a5 = {
  red: 1,
};
console.log(a6.red);

// 6. const 枚举
const enum a7 {
  success,
  fail,
}
let code: number = 0;
if (code === a7.success) {
  console.log(1); // 1
}
enum a8 {
  success,
  fail,
}
let code1: number = 0;
if (code1 === a8.success) {
  console.log(12); // 12
}

//   7.反向映射
enum a9 {
  success,
}
let success: number = a9.success;
console.log(success); // 0

let a10 = a9[success];
console.log(a10); // success

12.类型推论和类型别名.ts

let str = "123";
// str = 1;    // 不能将类型"number"分配给类型"string".ts(2322)

// let a1; // 变量 "a1" 隐式具有 "any" 类型,但可以从用法中推断出更好的类型.ts(7043)
// a1 = "123";

type s = string;
let a2: s = "123";

type f = () => void;
let a3: f = function () {};
a3();

//   高级用法
//   number any unknow object 都是 返回 1
//   1. any unknown
//   2. Object
//   3. Number
//   4. number string
//   5. never
type num = 1 extends number ? 1 : 0; // true
let a4: num = 1;

13-never.ts

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

function a2(): never {
  while (true) {
    switch (true) {
      default:
        break;
    }
  }
}

type a3 = void | number | never; // type a = number | void

type a5 = "a" | "b" | "c" | "d";
function a4(value) {
  switch (value) {
    case "a":
      console.log("a");
      break;
    case "b":
      console.log("b");
      break;
    case "c":
      console.log("c");
      break;
    case "d":
      console.log("d");
      break;
    default:
      // type a5 = "a" | "b" | "c" | "d" | "dd"
      // 不能将类型"any"分配给类型"never".
      // const error: never = value;
      break;
  }
}

14-symbol.ts

let a1: Symbol = Symbol("1");
let a2: Symbol = Symbol("2");
console.log(a1);
console.log(a2);
console.log(a1 == a2); // false

//   for 会去全局里面找,有的话直接用不去找,如果没有的话就去创建个
//   所以第二个就是用的第一个
console.log(Symbol.for("a1") === Symbol.for("a1")); // true

let a3 = {
  name: 1,
  // [a1]: 111,
  // [a2]: 222,
};
console.log(a3);
//   for in 不能读取 symbol 类型的属性
//   Object.keys  不能读取 symbol 类型的属性
//   Object.getOwnPropertyNames 不能读取 symbol 类型的属性

//   可以取到 Symbol 但是娶不到普通的
Object.getOwnPropertySymbols(a3);

//   可以取到所有
Reflect.ownKeys(a3);

15-生成器和迭代器.ts

// 1. 生成器
function* gen() {
  yield Promise.resolve(1);
  yield 2;
  yield 3;
}
const a1 = gen();
console.log(a1.next()); // {value: Promise, done: false}
console.log(a1.next()); // {value: 1, done: false}
console.log(a1.next()); // {value: 1, done: false}
console.log(a1.next()); // {value: undefined, done: true}

//   2. 迭代器

//   3. set 和 map
let set: Set<number> = new Set([1, 2, 3, 1, 1, 2]);
console.log(set); // Set(3) {1, 2, 3}

let map: Map<any, any> = new Map();
let arr = [1, 2, 3, 4, 5];
map.set(arr, "a");
console.log(map.get(arr)); // a

function args() {
  console.log(arguments); // 伪数组
}
let list = document.querySelectorAll("li"); // 伪数组

const each = (value: any) => {
  let it: any = value[Symbol.iterator]();
  let next: any = { done: false };
  while (!next.done) {
    next = it.next();
    if (!next.done) {
      console.log(next.value);
    }
  }
};
// bundle.js:2 1
// bundle.js:2 2
// bundle.js:2 3
// bundle.js:2 4
// bundle.js:2
each(arr);
each(set);

//   5. 迭代器语法糖
for (const value of arr) {
  console.log(value);
}
//   for of 对象不可用
// 对象身上没有 Symbol.iterator
for (const value of set) {
  console.log(value);
}

//   6. 解构 的底层也是 iterator
console.log("------------------------------");

let obj = {
  max: 5,
  cou: 0,
  [Symbol.iterator]() {
    return {
      max: this.max,
      cou: this.cou,
      next: () => {
        if (this.cou === this.max) {
          return { value: undefined, done: true };
        } else {
          return {
            value: this.cou++,
            done: false,
          };
        }
      },
    };
  },
};
//   类型"{ max: number; cou: number; }"必须具有返回迭代器的 "[Symbol.iterator]()" 方法.ts(2488)
for (const value of obj) {
  console.log(value);
}
let x = { ...obj };
console.log(x);
//   {
//     "max": 5,
//     "cou": 5
// }

16-泛型.ts

function a1(a: number, b: number): Array<number> {
  return [a, b];
}
//   1. 函数使用泛型
function a2<T>(a: T, b: T): Array<T> {
  return [a, b];
}
console.log(a2(1, 2)); //  (2) [1, 2]
console.log(a2("1", "2")); // (2) ['1', '2']

//   2. type 使用
type a3<T> = string | number | T;
let a4: a3<boolean> = true;
let a5: a3<undefined> = undefined;
let a6: a3<null> = null;

//   3. interface 使用
interface a7<T> {
  msg: T;
}
let a8: a7<boolean> = {
  msg: true,
};
let a9: a7<number> = {
  msg: 1,
};
//   4. 其他用法
function a10<T = number, K = string>(a: T, b: K): Array<T | K> {
  return [a, b];
}
console.log(a10(1, 2)); //  (2) [1, 2]
console.log(a10(1, "2")); //  (2) [1, '2']

//   5. 实战
const axios = {
  get<T>(url: string): Promise<T> {
    return new Promise((res, err) => {
      let xhr: XMLHttpRequest = new XMLHttpRequest();
      xhr.open("GET", url);
      xhr.onreadystatechange = function () {
        if (xhr.readyState === 4) {
          if (xhr.status === 200) {
            res(JSON.parse(xhr.responseText));
          } else {
            err(xhr.status);
          }
        }
      };
      xhr.send(null);
    });
  },
};
interface Data {
  message: string;
  code: number;
}
axios.get<Data>("./16.json").then((res) => {
  console.log(res.message);
});

16json

{
  "code": 200,
  "message": "success"
}

17-泛型.ts

// 在类型的侯建跟上一个 extends 在跟一个约束的类型
function add<T extends number>(a: T, b: T) {
  return a + b;
}
add(1, 2);

interface Len {
  length: number;
}
function a2<T extends Len>(a: T) {
  return a.length;
}
console.log(a2("123"));

let obj = {
  name: "123",
  sex: "1",
};

function a3<T extends object, K extends keyof T>(obj: T, key: K) {
  return obj[key];
}
console.log(a3(obj, "name")); // 123

interface Data {
  name: string;
  age: number;
  sex: string;
}
type Options<T extends object> = {
  [K in keyof T]?: T[K];
};
type B = Options<Data>;
//   type B = {
//     name?: string;
//     age?: number;
//     sex?: string;
//   };

18.tsconfig.json


"compilerOptions": {
    "incremental": true, // TS编译器在第一次编译之后会生成一个存储编译信息的文件,第二次编译会在第一次的基础上进行增量编译,可以提高编译的速度
    "tsBuildInfoFile": "./buildFile", // 增量编译文件的存储位置
    "diagnostics": true, // 打印诊断信息
    "target": "ES5", // 目标语言的版本
    "module": "CommonJS", // 生成代码的模板标准
    "outFile": "./app.js", // 将多个相互依赖的文件生成一个文件,可以用在AMD模块中,即开启时应设置"module": "AMD",
    "lib": ["DOM", "ES2015", "ScriptHost", "ES2019.Array"], // TS需要引用的库,即声明文件,es5 默认引用dom、es5、scripthost,如需要使用es的高级版本特性,通常都需要配置,如es8的数组新特性需要引入"ES2019.Array",
    "allowJS": true, // 允许编译器编译JS,JSX文件
    "checkJs": true, // 允许在JS文件中报错,通常与allowJS一起使用
    "outDir": "./dist", // 指定输出目录
    "rootDir": "./", // 指定输出文件目录(用于输出),用于控制输出目录结构
    "declaration": true, // 生成声明文件,开启后会自动生成声明文件
    "declarationDir": "./file", // 指定生成声明文件存放目录
    "emitDeclarationOnly": true, // 只生成声明文件,而不会生成js文件
    "sourceMap": true, // 生成目标文件的sourceMap文件
    "inlineSourceMap": true, // 生成目标文件的inline SourceMap,inline SourceMap会包含在生成的js文件中
    "declarationMap": true, // 为声明文件生成sourceMap
    "typeRoots": [], // 声明文件目录,默认时node_modules/@types
    "types": [], // 加载的声明文件包
    "removeComments":true, // 删除注释
    "noEmit": true, // 不输出文件,即编译后不会生成任何js文件
    "noEmitOnError": true, // 发送错误时不输出任何文件
    "noEmitHelpers": true, // 不生成helper函数,减小体积,需要额外安装,常配合importHelpers一起使用
    "importHelpers": true, // 通过tslib引入helper函数,文件必须是模块
    "downlevelIteration": true, // 降级遍历器实现,如果目标源是es3/5,那么遍历器会有降级的实现
    "strict": true, // 开启所有严格的类型检查
    "alwaysStrict": true, // 在代码中注入'use strict'
    "noImplicitAny": true, // 不允许隐式的any类型
    "strictNullChecks": true, // 不允许把null、undefined赋值给其他类型的变量
    "strictFunctionTypes": true, // 不允许函数参数双向协变
    "strictPropertyInitialization": true, // 类的实例属性必须初始化
    "strictBindCallApply": true, // 严格的bind/call/apply检查
    "noImplicitThis": true, // 不允许this有隐式的any类型
    "noUnusedLocals": true, // 检查只声明、未使用的局部变量(只提示不报错)
    "noUnusedParameters": true, // 检查未使用的函数参数(只提示不报错)
    "noFallthroughCasesInSwitch": true, // 防止switch语句贯穿(即如果没有break语句后面不会执行)
    "noImplicitReturns": true, //每个分支都会有返回值
    "esModuleInterop": true, // 允许export=导出,由import from 导入
    "allowUmdGlobalAccess": true, // 允许在模块中全局变量的方式访问umd模块
    "moduleResolution": "node", // 模块解析策略,ts默认用node的解析策略,即相对的方式导入
    "baseUrl": "./", // 解析非相对模块的基地址,默认是当前目录
    "paths": { // 路径映射,相对于baseUrl
      // 如使用jq时不想使用默认版本,而需要手动指定版本,可进行如下配置
      "jquery": ["node_modules/jquery/dist/jquery.min.js"]
    },
    "rootDirs": ["src","out"], // 将多个目录放在一个虚拟目录下,用于运行时,即编译后引入文件的位置可能发生变化,这也设置可以虚拟src和out在同一个目录下,不用再去改变路径也不会报错
    "listEmittedFiles": true, // 打印输出文件
    "listFiles": true// 打印编译的文件(包括引用的声明文件)
  }

  // 指定一个匹配列表(属于自动指定该路径下的所有ts相关文件)
  "include": [
     "src/**/*"
  ],
  // 指定一个排除列表(include的反向操作)
   "exclude": [
     "demo.ts"
  ],
  // 指定哪些文件使用该配置(属于手动一个个指定文件)
   "files": [
     "demo.ts"
  ]

19-namespace.ts

namespace A {
  export namespace B {
    export namespace C {
      export const a = 1;
    }
  }
}
import AAA = A.B.C;
console.log(AAA.a);

namespace D {
  export const a = 1;
}
namespace D {
  export const b = 2;
}
console.log(D);
// {
//     "a": 1,
//     "b": 2
// }

20-三斜线

20-三斜线-1.ts

///<reference path='20-三斜线-2.ts' />

namespace A {
  export const e = 1;
}

console.log(A);

20-三斜线-2.ts

namespace A {
  export const fn = () => "a";
}

21-声明文件.ts

22-Mixins 混入.ts

interface Name {
  name: string;
}
interface Age {
  age: number;
}
interface Sex {
  sex: string;
}
let a: Name = { name: "name" };
let b: Age = { age: 10 };
let c: Sex = { sex: "sex" };
let obj = Object.assign({}, a, b, c);
//   {
//     "name": "name",
//     "age": 10,
//     "sex": "sex"
// }
console.log(obj);

class A {
  type: boolean;
  changeType() {
    this.type = !this.type;
  }
}
class B {
  name: string;
  getName(): string {
    return this.name;
  }
}
class C implements A, B {
  type: boolean = false;
  name: string = "name";
  changeType: () => void;
  getName: () => string;
}
mixins(C, [A, B]);
function mixins(curClass: any, itemClass: any[]) {
  itemClass.forEach((item) => {
    console.log(item);
    Object.getOwnPropertyNames(item.prototype).forEach((name) => {
      curClass.prototype[name] = item.prototype[name];
    });
  });
}
let ccc = new C();
ccc.changeType();
console.log(ccc.getName()); // name

23-装饰器 Decorator.ts

import "reflect-metadata";
(function () {
  // 1. 类装饰器 ClassDecorator target
  const Base: ClassDecorator = (target) => {
    console.log(target);
    target.prototype.xiaman = "lgq";
    target.prototype.fn = () => {
      console.log("123");
    };
  };
  @Base
  class Http {}
  const http = new Http() as any;
  http.fn(); // 123
  console.log(http.xiaman); // lgq
  //   Base(Http); 等同 @Base

  // 2. 属性装饰器

  const Name:PropertyDecorator=(target,key)=>{
    console.log(target); // {}
    console.log(key);   // LGQ
  }
  class Http2 {
    name: string;
    @Name
    constructor(name: string) {
      this.name = 'LGQ';
    }
  }

  // 3. 方法装饰器
  const Get = (url: string) => {
    const fn: MethodDecorator = (target, key, des) => {
      console.log(url); // www.baidu.com
      console.log(target); // {constructor: ƒ, getList: ƒ, create: ƒ}
      console.log(key); // getList
      console.log(des); // {writable: true, enumerable: false, configurable: true, value: ƒ}
    };
    return fn;
  };
  class Http2 {
    @Get("www.baidu.com")
    getList(data: any) {
      console.log(data);
    }
  }
  // 4. 参数装饰器

  const Get4 = (url: string) => {
    const fn: MethodDecorator = (target, key, des: PropertyDescriptor) => {
      const key = Reflect.getMetaData("key", target);
      axios.get(url).then((res) => {
        desc.value(key ? res.data[key] : res.data);
      });
      //   console.log(url); // www.baidu.com
      //   console.log(target); // {constructor: ƒ, getList: ƒ, create: ƒ}
      //   console.log(key); // getList
      //   console.log(des); // {writable: true, enumerable: false, configurable: true, value: ƒ}
    };
    return fn;
  };
  const Result = (): ParameterDecorator => {
    const fn: ParameterDecorator = (target, key, index) => {
      //   console.log(target); // {constructor: ƒ, getList: ƒ}
      //   console.log(key); // getList
      //   console.log(index); // 0
      Reflect.defineMetadata("key", "result", target); // 给对象添加元数据
    };
    return fn;
  };
  class Http4 {
    @Get4("www.baidu.com")
    // @Result() 对 data 进行二次处理
    getList(@Result() data: any) {
      console.log(data);
    }
  }

  // 5. 装饰器工厂
  const Base1 = (name: string) => {
    const fn: ClassDecorator = (target) => {
      console.log(target);
      target.prototype.xiaman = name;
      target.prototype.fn = () => {
        console.log("123");
      };
    };
    return fn;
  };
  @Base1("LGQ")
  class Http1 {}
  const http1 = new Http1() as any;
  http1.fn(); // 123
  console.log(http1.xiaman); // LGQ
  // 6. import 'reflect-metadata'
  // 7. axios
})();

24-rollupTS

rollup.config.js

console.log(process.env);
import ts from "rollup-plugin-typescript2";
import path from "path";
import serve from "rollup-plugin-serve";
import livereload from "rollup-plugin-livereload";
import { terser } from "rollup-plugin-terser";
import resolve from "rollup-plugin-node-resolve";
import repacle from "rollup-plugin-replace";

const isDev = () => {
  return process.env.NODE_ENV === "development";
};
export default {
  input: "./src/main.ts",
  output: {
    file: path.resolve(__dirname, "./lib/index.js"),
    format: "umd",
    sourcemap: true,
  },

  plugins: [
    ts(),
    terser({
      compress: {
        drop_console: !isDev(),
      },
    }),
    repacle({
      "process.env.NODE_ENV": JSON.stringify(process.env.NODE_ENV),
    }),
    resolve([".js", ".ts"]),
    isDev() && livereload(),
    isDev() &&
      serve({
        open: true,
        openPage: "/public/index.html",
      }),
  ],
};

package.json

{
  "name": "rollupTs",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "cross-env NODE_ENV=development  rollup -c -w",
    "build": "cross-env NODE_ENV=produaction  rollup -c"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "cross-env": "^7.0.3",
    "rollup-plugin-livereload": "^2.0.5",
    "rollup-plugin-node-resolve": "^5.2.0",
    "rollup-plugin-replace": "^2.2.0",
    "rollup-plugin-serve": "^1.1.0",
    "rollup-plugin-terser": "^7.0.2",
    "rollup-plugin-typescript2": "^0.31.1",
    "typescript": "^4.5.5"
  }
}

25-webpackTS

package.json

{
  "name": "25-webpackts",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack",
    "start": "webpack server"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "html-webpack-plugin": "^5.5.3",
    "ts-loader": "^9.4.4",
    "typescript": "^5.2.2",
    "webpack": "^5.88.2",
    "webpack-cli": "^5.1.4",
    "webpack-dev-server": "^4.15.1"
  }
}

webpack.config.js

const path = require("path");
const htmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
  entry: "./src/index.ts",
  mode: "development",
  output: {
    path: path.resolve(__dirname, "./dist"),
    filename: "index.js",
  },
  stats: "none",
  resolve: {
    extensions: [".ts", ".js"],
    alias: {
      "@": path.resolve(__dirname, "./src"),
    },
  },
  module: {
    rules: [
      {
        test: /\.ts$/,
        use: "ts-loader",
      },
    ],
  },
  devServer: {
    port: 1988,
    proxy: {},
  },
  plugins: [
    new htmlWebpackPlugin({
      template: "./public/index.html",
    }),
  ],
};

26-esbuild-swc

package.json

{
  "name": "26-esbuild-swc",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "type": "module",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "@swc/core": "^1.3.85",
    "@swc/helpers": "^0.5.2",
    "esbuild": "^0.19.3"
  }
}

config.ts

import esbuild from "esbuild"; //打包工具
import swc from "@swc/core"; //类似于babel es6 转 es5
import fs from "node:fs";
await esbuild.build({
  entryPoints: ["./index.ts"],
  bundle: true,
  loader: {
    ".js": "js",
    ".ts": "ts",
    ".jsx": "jsx",
    ".tsx": "tsx",
  },
  treeShaking: true,
  define: {
    "process.env.NODE_ENV": '"production"',
  },
  plugins: [
    {
      //实现自定义loader
      name: "swc-loader",
      setup(build) {
        build.onLoad({ filter: /\.(js|ts|tsx|jsx)$/ }, (args) => {
          // console.log(args);
          const content = fs.readFileSync(args.path, "utf-8");
          const { code } = swc.transformSync(content, {
            filename: args.path,
          });
          return {
            contents: code,
          };
        });
      },
    },
  ],
  outdir: "dist",
});

27-localstorage

src\enum\index.ts

export enum Dictionaries {
  permanent = "permanent",
  expire = "__expire__",
}
// 字典类型

src\type\index.ts

import { Dictionaries } from "../enum";
export interface StorageCls {
  get: <T>(key: Key) => void;
  set: <T>(key: Key, value: T, expire: Expire) => void;
  remove: (key: Key) => void;
  clear: () => void;
}
export interface Data<T> {
  value: T;
  [Dictionaries.expire]: Expire;
}
export interface Result<T> {
  message: string;
  value: T | null;
}
export type Key = string;
export type Expire = number | Dictionaries.permanent;

src\index.ts

import { StorageCls, Key, Expire, Data, Result } from "./type";
import { Dictionaries } from "./enum";
class Storage implements StorageCls {
  set<T>(key: Key, value: T, expire: Expire = Dictionaries.permanent) {
    const data = {
      value,
      [Dictionaries.expire]: expire, // 过期事件
    };
    localStorage.setItem(key, JSON.stringify(data));
  }
  get<T>(key: Key): Result<T | null> {
    const value = localStorage.getItem(key);
    if (value) {
      const data: Data<T> = JSON.parse(value);
      const now = new Date().getTime();
      if (
        typeof data[Dictionaries.expire] == "number" &&
        data[Dictionaries.expire] < now
      ) {
        // 过期了
        return {
          message: `${key},过期了`,
          value: null,
        };
        this.remove(key);
      } else {
        return {
          message: `成功`,
          value: data.value,
        };
      }
    } else {
      return {
        message: "数据无效",
        value: null,
      };
    }
  }
  remove(key: Key) {
    localStorage.removeItem(key);
  }
  clear() {
    localStorage.clear();
  }
}
export default Storage;

28-发布订阅模式

interface Evenet {
  on: (name: string, fn: Function) => void;
  emit: (name: string, ...args: Array<any>) => void;
  off: (name: string, fn: Function) => void;
  once: (name: string, fn: Function) => void;
}

interface List {
  [ket: string]: Array<Function>;
}
class Dispatch implements Evenet {
  list: List;
  constructor() {
    this.list = {};
  }
  on(name: string, fn: Function) {
    const callback = this.list[name] || [];
    callback.push(fn);
    this.list[name] = callback;
    console.log(this.list);
  }
  off(name: string, fn: Function) {
    let eventName = this.list[name];
    if (eventName) {
      let index = eventName.findIndex((fns) => fns === fn);
      eventName.splice(index, 1);
    } else {
      console.log(name + "--->no event");
    }
  }
  emit(name: string, ...args: Array<any>) {
    let eventName = this.list[name];
    if (eventName) {
      eventName.forEach((fn: Function) => {
        fn.apply(this, args);
      });
    } else {
      console.log(name + "--->no event");
    }
  }
  once(name: string, fn: Function) {
    let de = (...args: Array<any>) => {
      fn.apply(this, args);
    };
    this.off(name, de);
  }
}
const o = new Dispatch();

const fn = (...args: Array<any>) => {
  console.log(args);
};
const fn1 = () => {
  console.log("fn1");
};
o.on("a", fn1); // fn1
// o.off("a", fn1);
o.emit("a", "4564", "456464");
o.once("a", fn); //  ['false', 'dadadada']

o.emit("a", "false", "dadadada");

29-proxy

// let person = {
//   name: "John",
//   age: 24,
// };
// let personProxy = new Proxy(person, {
// get(target, prop) {},
// set(target, prop, value, receiver) {},
// // 拦截函数调用
// apply() {},
// // 拦截in操作符
// has() {},
// // 拦截 forin
// ownKeys() {},
// // 拦截 new 操作符
// construct() {},
// // 拦截删除操作
// deleteProperty() {},
// });

let person = {
  name: "John",
  age: 24,
};
let personProxy = new Proxy(person, {
  get(target, prop, receiver) {
    if (target.age <= 18) {
      return Reflect.get(target, prop, receiver);
    } else {
      return "This person is allowed to see this information.";
    }
  },
});
console.log(personProxy.age);
console.log(Reflect.get(personProxy, "age", personProxy));

const list: Set<Function> = new Set();
const autofun = (cb: Function) => {
  if (!list.has(cb)) {
    list.add(cb);
  }
};
const observable = <T extends object>(params: T) => {
  return new Proxy(params, {
    set(target, prop, value, receiver) {
      console.log("set");
      const result = Reflect.set(target, prop, value, receiver);
      list.forEach((cb) => cb());
      return result;
    },
    get(target, prop, receiver) {
      console.log("get");
      return Reflect.get(target, prop, receiver);
    },
  });
};
const personObersver = observable({
  name: "John",
  age: 24,
});
autofun(() => {
  console.log("变化;了");
});
personObersver.name = "Mike";
personObersver.name = "M111ike";

30-TS 进阶

1-协变,逆变

// 主类型
interface A {
  name: string;
  age: number;
}
// 子类型
interface B {
  name: string;
  age: number;
  sex: string;
}
// a b 就是鸭子类型
let a: A = {
  name: "zhangsan",
  age: 18,
};
let b: B = {
  name: "zhangsan",
  age: 18,
  sex: "male",
};

// 协变类型
// 主类型 相比较 子类型 不可以少但是可以多
a = b;
// b = a;  // 类型 "A" 中缺少属性 "sex",但类型 "B" 中需要该属性.

// 逆变类型
// 主类型 相比较 子类型 不可以多但是可以少
let fna = (params: A) => {};
let fnb = (params: B) => {};
fnb = fna;

// fna = fnb;
// 不能将类型"(params: B) => void"分配给类型"(params: A) => void".
// 参数"params"和"params" 的类型不兼容.
// 类型 "A" 中缺少属性 "sex",但类型 "B" 中需要该属性.

2-weakmap 和 weakset

// 1. Set
// 自动去重,但是引用类型除外
let set: Set<number> = new Set([1, 2, 7, 7, 10]);
console.log(set); // Set(4) {1, 2, 7, 10}
set.add(100);
console.log(set); // Set(5) {1, 2, 7, 10, 100}
set.delete(100);
console.log(set); // Set(4) {1, 2, 7, 10}
set.clear();
console.log(set); // Set(0) {size: 0}

// 2. Map
let obj = {
  name: "zfpx",
};
let map: Map<object, any> = new Map();
map.set(obj, "zfpx");
console.log(map);
// new Map([
//   [
//     {
//       name: "zfpx",
//     },
//     "zfpx",
//   ],
// ]);
// 方法和 set 一样,都很多

// 3. weakMap  WeakSet 弱引用类型 不会被记录垃圾回收策略
let a1: any = { name: "123" }; //1 次引用
let a2: any = a1; // 2 次引用
let weakmap: WeakMap<object, any> = new WeakMap();
// weakmap 的 key 只能是引用类型
weakmap.set(a1, "zfpx"); // 2
console.log(weakmap.get(a1)); // zfpx

a1 = null; // -1 次应用 还剩 1次
a2 = null;

console.log(weakmap.get(a1)); // undefined

let weakset = new WeakSet([a1, a2]);
console.log(weakset);

3-Pick 和 partail

// 1. Partial 把每个类型处理哼可选的
type Person = {
  name: string;
  age: number;
  text: string;
};
type p1 = Partial<Person>;
// type p = {
//   name?: string | undefined;
//   age?: number | undefined;
//   text?: string | undefined;
// };

// 这个方法是实现 Partial
type Partial<T> = {
  [P in keyof T]?: T[P];
};

// 2. Pick
type p2 = Pick<Person, "name" | "age">;
// type p2 = {
//   name: string;
//   age: number;
// };
// 这个方法是实现 Pick
type Pick<T, K extends keyof T> = {
  [P in K]: T[P];
};

4-readonly 和 record

type Person = {
  name: string;
  age: number;
  text: string;
};
type R<T> = {
  readonly [P in keyof T]: T[P];
};
type PersonR = R<Person>;
// type PersonR = {
//   readonly name: string;
//   readonly age: number;
//   readonly text: string;
// };

// keyof any 返回 type key = string | number | symbol
type Rec<K extends keyof any, T> = {
  [p in K]: T;
};
type K = "A" | "B" | "C";

type B = Rec<K, Person>;
// type B = {
//   A: Person;
//   B: Person;
//   C: Person;
// };
let obj: B = {
  A: {
    name: "A",
    age: 1,
    text: "A",
  },
  B: {
    name: "B",
    age: 2,
    text: "B",
  },
  C: {
    name: "C",
    age: 3,
    text: "C",
  },
};

5-infer 关键字

// 1. 定义一个类型,如果是数组类型,就返回数组元素的类型,否则传入什么类型就返回什么类型
type Type<T> = T extends Array<infer U> ? U : T;
{
}
type A = Type<string>; // type A = string
type B = Type<number | string>; // type B = string | number
type C = Type<(number | string)[]>;
// const c: C = [false]; // 不能将类型"boolean[]"分配给类型"string | number"

type T = [string, number, boolean];
type uni = Type<T>; // type uni = string | number | boolean

6-infer 提取元素

type Arr = ["a", "b", "c"];

// 取第一个
type First<T extends any[]> = T extends [infer one, ...any[]] ? one : [];
type a = First<Arr>; // type a = "a"

// 取最后一个
type Last<T extends any[]> = T extends [...any[], infer last] ? last : [];
type b = Last<Arr>; // type b = "c"

// 取除去最后一个
type Pop<T extends any[]> = T extends [...infer Rest, unknown] ? Rest : [];
type c = Pop<Arr>; // type c = ["a", "b"]

// 取除去第一个
type Shift<T extends any[]> = T extends [unknown, ...infer Rest] ? Rest : [];
type d = Shift<Arr>; // type d = ["b", "c"]

7-infer 递归

type Arr = [1, 2, 3];

// 把 Arr 颠倒顺序
type ReverArr<T extends any[]> = T extends [infer First, ...infer rest]
  ? [...ReverArr<rest>, First]
  : T;

type Arr1 = ReverArr<Arr>; //