前端进阶1-TypeScript

244 阅读11分钟
  • 1.TypeScript\

    • 为什么需要TS?\

      • TS提供了一套静态检测机制, 可以帮助我们在编译时就发现错误\
    • TS由什么组成?\

      • ECMAScipt、DOM、BOM\
    • 基本操作:\

      • ts:\

        • 生成配置文件:tsc -init\
        • 编译:tsc\
        • 动态编译:tsc index.ts --watch\
        • 创建文件: echo ''>index.ts\
      • ts-node:\

        • 编译并执行,不生成js文件:ts-node index.ts\
    • 1.基础类型、任意类型(TS最主要的特点就是可以定义静态类型)\

      • 一旦定义就不可改变(例子:let count: number = 1,count不可改变,而且可以用number类型的所有方法)\
      • 基础静态类型(Boolean、Number、String、Null、Undefined、Symbol、Bigint)\

        • Number可以包含:NaN、普通数字、无穷大infinity、十进制、十六进制\
        • void概念:(函数没有return返回值的时候用)\

          • 空值,接收undefined和null\
          • void和undefined的区别:void不能赋值给别人,undefined可以\
          • 写在函数上,函数不能return\
        • any和unknown的区别:unknown比any更加安全\
      • 对象静态类型(Object、[Array、tuple]、Class、Function、Enum、Any、Unknown、never)\

        • unknown\

          • 不能去调用属性和方法\
          • 不能当作子类型赋值给别人,要赋值只能赋值给unknown或any\
        • object对象类型、array数组类型、class类类型、function函数类型\
        • enum枚举、any任何、unknown未知\
        • tuple元组:\

          • 概念:定义具有有限数量的未命名属性的类型\
          • 特性:可以限制数组元素的个数和类型,它特别适合用来实现多值返回。\
        • never概念:如果异常或死循环,程序被中断了,没有返回值,就在函数后写:never\
      • const fn: () => string,意思是定义的时候必须是一个函数,并且有返回值是string\
      • 类型注解annotation(给它标注let count: number)\
      • 类型推断inference(自己推断)\
      • 返回参数和返回类型的注解:function getNumber({ one, two }: { one: number; two: number }){}\
      • 数组类型注解:const numberArr: number[] = [1, 2, 3];\
    • 3.接口Interface(定义数据类型)和对象类型\

      • 接口Interface\

        • 定义数据类型,如果重名两个接口会合并定义\
        • 它是对行为的抽象,而具体如何行动需要由类(classes)去实现(implement)。可用于[对类的一部分行为进行抽象]以外,也常用于对「对象的形状(Shape)」进行描述\
        • 可选式操作符?属性是可选的,可以有也可以没有这个值\
        • 内置变量(propName: string):any:属性名是string,属性是any。一般是any因为不知道后台返回什么\
        • 联合类型|:\
        • 只读属性readonly:是只读的,定义后不能再赋值了\
      • 对象类型\
    • 4.数组类型\

      • 数组定义::number、:string、:boolean、:any(常用)\
      • 数组泛型定义:: Array、: Array、: Array\
      • 多维数组定义:let arr: number[][][] = [[[]], [[]], [[]]];\
      • 多维数组泛型定义:let arr: Array<Array> = [[], [], []];\
      • 类数组arguments:let arr: IArguments = arguments;\
    • 5.函数类型(函数重载)\

      • 函数定义:function (name: string, age?: number): string\
      • 接口Interface约束类型:\

        • interface User {name: string;age?: number;}\
        • function (user: User): User { return user }\
      • 函数重载(重点)\

        • 概念:重载是方法名字相同,但参数不同,返回类型可以相同也可以不同。如果参数类型不同,则操作函数参数类型应设置为any。参数数量不同你可以将不同的参数设置位可选。\
        • function fn(params: number): void;(重载函数-规则)\
        • function fn(params: string, params2: number): void;(重载函数-规则)\
        • function fn(params: any, params2?: any): any {return params;}(执行函数-逻辑)\
    • 6.类型断言 | 联合类型 | 交叉类型\

      • 类型断言( as或A> )\

        • 第一种方法:(num as string).length\
        • 第二种方法:(A>type).run\
        • 只是欺骗ts,不能避免运行错误,不能滥用断言。\
        • 临时断言:\

          • (window as any).abc = 123;\
          • any可以被断言成任何类型\
        • return type as boolean;会欺骗TS,不能乱用\
      • 联合类型( | )\

        • let phone: number | string = 18598252994;\
        • 声明函数使用:let fn = function (type: number | boolean): boolean {return !!type;};\
        • 注释:!!是强制转布尔值\
      • 交叉类型( & )\

        • interface Pople {name: string;age: number;}\
        • interface Man {sex: number;}\
        • const czy = (man: Pople & Man): void => {console.log();};\
    • 7.内置对象(Promise对象)\

      • ECMAScipt的内置对象\

        • 正则表达式(regular expression):const regexp: RegExp = /\w\d\s/;\
        • 日期(Date ):const date: Date = new Date();\
        • 错误(Error):const error: Error = new Error("错误");\
      • DOM的内置对象\

        • 节点列表(NodeList )\

          • const list: NodeList = document.querySelectorAll("#list li");\
          • 和arguments不一样,打印出来是类数组有forEach、item、keys、values方法\
        • HTML元素(HTMLElement)\

          • const body: HTMLElement = document.body;\
        • Div元素(HTMLDivElement)\

          • const div: HTMLDivElement = document.querySelector("div");\
      • BOM的内置对象\

        • 鼠标事件(MouseEvent)\

          • document.addEventListener("click", (e: MouseEvent) => {console.log(e);});\
      • Promise对象(Promise)\

        • function promise(): Promise {return new Promise((resolve, reject) => {resolve(1);});}\
    • 8.1.Class 类类型\

      • 定义类\

        • class ClassName{ name:string; constructor(name:string){this.name=name} }\
      • 类的修饰符\

        • public(共用变量)内部和外部都能访问\
        • private(私有的)私有变量只能在内部访问\
        • protected(受保护的)内部和子类中能访问\
      • 静态属性\

        • static(静态属性)自定义属性,不需要new,通过类名ClassName访问\
        • 静态函数\

          • static run(): string {return "run()"; }\
          • 静态函数只能访问static静态属性(因为静态函数的this指的是当前这个类,而构造函数里面的this指的是新的实例对象)\
          • 静态函数和内部变量双向不能调用。只能ClassName.run()\
      • interface接口(约束Class)\

        • interface Person {run(type: boolean): boolean;}\
        • interface H {set(): void;}\
        • class Man implements Person, H {run(type: boolean): boolean {return type; }set() {}}\
      • 继承extends\

        • super可以让子调用父的属性和方法\
      • 子类调用父类,必须调用父类的constructor,用super('张三')\
    • 8.2.抽象类(abstract)\

      • abstract class A {name: string;constructor(name: string) {[this.name](this. name) = name; }abstract getName(): string;}\
      • 抽象类不能被new实例化,要去派生类(class)里面实现\
    • 9.元组(Tuple)\

      • let arr: [string, number] = ["张三", 1];\
      • 应用场景(二维数组):let excel: [string, string, number][] = [["title", "name", 1]];\
    • 10.枚举类型(Enum)\

      • 数组枚举enum Color {red,green,blue,}(自动从0,1,2开始增长)\
      • 增长枚举enum Color {red = 3,green,blue,}(自动从3,4,5开始增长)\
      • 字符串枚举enum Color {red = "red",green = "green",blue = "blue",}\
      • 异构枚举enum Color {no = "no",yes = 1,}\
      • 接口枚举interface A {red: Color.yes;}\
      • const枚举(用了会编译成常量,不用会编译成对象)\
      • 反向映射:\

        • enum Types {success = 456,}\
        • let suc: number = Types.success;\
        • let key = Types[suc];(数字支持反射,字符串不支持反射)\
        • Types[Types["success"] = 456] = "success";\
    • 11.类型推断 | 类型别名\

      • 类型推断let str = "张三";\
      • 类型别名\

        • 联合(type str = string | number;)\

          • let str: str = "张三";let num: str = 123;\
        • 函数(type cb = () => string;)\

          • const fn: cb = () => "张三";\
        • 值(type T = "off" | "on" | false | 5;)\
        • let str: T = false;\
    • 12.Never 类型\

      • type bbb = string & number;\
      • 出现never可能声明有问题\
      • 抛出错误或无限循环函数用never\
      • 在switch(type){case 'a'; break;}中 defined\
    • 13.1.上集 Symbol 类型\

      • let s: symbol = Symbol();\

        • 字符串或数字,不建议传对象或数组\
        • 内存地址指针位置不同所以是唯一值\
      • 作用:一般用于对象属性的键值\
      • 和基本属性的区别:\

        • for-in循环obj、Object.keys(obj)、Object.getOwnPropertyNames(obj)、JSON.stringify(obj)时,不能得到symbol键值\
        • Object.getOwnPropertySymbols(obj)时,能得到symbol键值\
    • 13.2.下集 迭代器(Symbol.iterator) | 生成器(for-of循环)\

      • 迭代器(Symbol.iterator)\

        • 迭代器定义在经常使用的类型prototype里,如数组、arguments(类数组)、NodeList(类数组)、new Set()、new Map()\
        • 伪数组、类数组有iterator迭代器\
        • 对象object是没有iterator迭代器的,可以用for-in或values\
      • 生成器(for-of循环)\

        • 自动调用Set下的entries方法帮我们把函数取出来\
        • 和for-in循环的区别:\

          • for-in循环的是索引(对象),for-of循环的是值(数组)\
    • 🍗14.1.***函数泛型(TS中的重点)\

      • Vue3是通过TS编写的,用了非常多泛型\
      • 概念:\

        • 把数据类型参数化\
        • 泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。泛型就是把不能明确的类型,变成参数,名为类型参数,一般用T来表示。类型变量,它是一种特殊的变量,只用于表示类型而不是值\
      • 作用:\

        • 创建可重用的组件、灵活扩展、可以在编译时发现你的类型错误\
      • 手写泛型\
      • 函数式泛型\

        • 单类型function add(a: T, b: T): Array {return [a, b];}\
        • 多类型function sub<T, U>(a: T, b: U): Array<T | U> {let arr: Array<T | U> = [a, b];return arr;}\
      • 泛型约束\

        • 先定义接口约束\

          • interface Len {length: number;}\
        • 在泛型时extends继承接口\

          • function getLength(arg: T) {return arg.length;}\
    • 🍗14.2.泛型约束(keyof) | 泛型类\

      • 约束对象的key(keyof)\

        • function prop<T, K extends keyof T>(obj: T, key: K) {return obj[key];}\
        • 用keyof分割T,T是传过来的对象,分割成联合类型\
        • 约束对象的key,避免对象的key值没有的时候TS不会提示\
      • 泛型类\

        • class Sub {attr: T[] = [];add(a: T): T[] {return [a]; }}\
        • 实例化:let num = new Sub();\
        • 实例化:let str = new Sub();\
    • 15.tsconfig.json 配置文件\

      • 编译指定的文件("include": ["./index.ts"],)执行tsc只有index.ts编译\
      • 不编译指定的文件("exclude": ["./index.ts"],)执行tsc只有index.ts不编译\
      • 删除注释("removeComments": true,)默认false\
      • 指定编译js的版本(es5、es6)\

        • ("target": "es2016", )默认es6\
        • 兼容低版本配置文件("target": "es5",)变成ES5\
      • 是否允许编译js文件("allowJs": true,)指引入js文件到TS中再编译\
      • 编译模式("module": "commonjs",)默认commonjs,可选es6模式、amd、umd等\
      • 编译代码源文件("sourceMap": true,)默认false,方便打包文件找错误\
      • 严格模式("strict": true,)默认开启\
    • 16.namespace 命名空间\

      • TypeScript与ECMAScript 2015一样,任何包含顶级import或export的文件都被当成一个模块。相反的,如果一个文件不带有顶级的import或export声明,那么它的内容被视为全局可见的。(因此对模块也是可见的)\
      • namespace 命名空间(namespace A {export const a = 1;})\

        • 会被编译成一个对象(包了一个function,是一个对象)\
        • 嵌套命名空间\

          • namespace A {\
          • export const a = 1;\
          • export namespace C {\
          • export const d = 5;\
          • }\
          • }\
          • A.C.d\
        • 抽离命名空间\

          • 概念:把命名空间抽离成一个文件\
          • 方法:export 命名空间,在其他文件import使用\
        • 简化命名空间\

          • 用import关键字\
          • 方法:import myA = A.C;拿到myA.d\
          • 注意:不能通过ts-node运行,不认识\
        • 命名空间的合并\

          • 重名的命名空间会自动合并\
    • 17.三斜线指令\

      • 1.引入其他TS文件(///)\
      • 2.声明文件(///)\

        • 安装node声明文件:npm install @types/node -D\
        • 声明文件一般是:@types/包名\
        • 它会去找node的index.ts声明文件\
    • 18.声明文件\

      • axios有指定TS声明文件,可以在TS文件中引入\
      • express没有指定声明文件,会报错\

        • 尝试使用 npm i --save-dev @types/express (如果存在),或者添加一个包含 declare module 'express'; 的新声明(.d.ts)文件\
      • 解决方法\

        • 1.declare(新建一个express.d.ts文件,写declare var express: () => any;,然后index.ts就可以直接用express()了)\
        • 2.npm i --save-dev @types/express\
      • @types 究竟是干什么的?\

        • 是做声明文件的\
    • 19.Mixins 混入(合并)\

      • 对象混入\

        • 合并对象(Object.assign(a, b, c);)是es6新增的\
        • let obj = Object.assign(a, b, c);得到(let obj: Name & Age & Sex)交叉类型\
      • 类的混入\
    • 20.修饰器 Decorator\

      • 好处:增加代码可读性,使用方便,增加或修改类的功能\
      • 配置文件启用:"experimentalDecorators": true,\
      • 构造修饰器:const watcher: ClassDecorator = () => {};\
      • 使用修饰器:@watcher\
    • 21.1.Rollup 构建 TS 项目\

      • 为什么选择Rollup?\

        • 因为webpack打包出来体积比较大,而Rollup打包体积比较小,适合开发小框架、小控件、小项目\
      • 入口文件(input: "./src/index.ts",)\
      • 出口文件(output: {file: path.resolve(__dirname, './lib/index.js'),format: 'umd' })\
      • 帮我们读tsconfig.json:import ts from 'rollup-plugin-typescript2'\
      • 启动网页:import serve from 'rollup-plugin-serve'\
      • 热更新:import livereload from 'rollup-plugin-livereload'\
      • 代码压缩:import { terser } from 'rollup-plugin-terser'\
      • 指定NODE_ENV的值:cross-env NODE_ENV=development\
      • 注册到全局都可以使用:import replace from 'rollup-plugin-replace'\
    • 21.2.webpack 构建 TS 项目\

      • 安装(NPM)\

        • :webpack-cli\
        • 热更新(自带):webpack-dev-server\
        • 帮我们解析TS:ts-loader\
        • HTML的模板:html-webpack-plugin\
      • 配置(webpack.config.js)\

        • const path = require('path')\
        • const htmpwebpackplug = require('html-webpack-plugin')\
        • entry入口、mode开发或生产、output出口、module模块、devServer启动配置、resolve文件后缀、plugins热更新\
    • 22.TS 编写发布订阅模式\

      • 发布订阅模式概述:收集事件做统一处理,例如addEventListener、Vue eventBus\
    • 23.TS 进阶 proxy(代理对象) 和 Reflect(操作对象get/set)\

      • proxy(对象形式代理)\

        • 手写实现事件监听器\
      • Reflect\

        • 概念:有一个对象,帮我们取值,操作对象(查找和设置)\
        • Reflect.get方法(查找值)\

          • 设let obj = { name:'张三' },执行Reflect.get( obj, 'name' ),查找输出'张三'\
        • Reflect.set方法(设置值)\

          • 设let obj = { name:'张三' },执行Reflect.set( obj, 'name','李四' ),修改设置obj = { name:'李四' }\
    • 24.TS 进阶用法 Partial(元素改为可选填) 和 Pick(元素摘选出新类型,过滤元素)\

      • TS内置该机类型Partial 和 Pick\
      • 设type Person = {name: string;age: number;text: string;};\
      • Partial类型\

        • 执行type p = Partial;,将Person取值全改为可选(?:)的了\
      • Pick类型\

        • 执行type p = Pick<Person, "age">;,将元素age摘选出新类型p,过滤元素\
    • 25.TS 进阶用法 Record(约束key和value) 和 Readonly(把每个属性变成只读的)\

      • Record\

        • type B = Record<K, Person>;\
        • 帮助我们约束key和value\
      • Readonly\

        • type man = Readonly;\
        • 每个元素面前加个readonly\
    • 26.TS 进阶用法 infer(充当占位符,实现条件类型推断)\

      • infer不是一个类型,一般用于extends后面\
    • 拓展知识:\

      • const path = require('path')\
      • path.resolve() 方法会将路径或路径片段的序列解析为绝对路径。\
      • path.join()方法拼接路径\