乐趣区

关于前端:TS基础

本文次要讲述动态类型、类型注解、类型推断、泛型、类型定义文件、模块化、打包编译、装璜器、Metadata、设计模式

一、概述

1.ts 是 js 的超集,ts 在浏览器或者 node 环境上不会间接执行,而是通过编译器编译成 js 后执行

2. 超集:ts 蕴含了 es5、es6 的所有语法,同时还蕴含了本人的新个性(可选的动态类型和基于类的面向对象编程)

3.TS 的劣势(绝对于 JS):


二、ts 环境

1.npm init -y (初始化 增加 package.json 文件)

1.npm install typescript@3.6.4 -g

2.tsc –init 初始化 ts 工程

3. 手动编译执行 ts:tsc demo.ts => 生成雷同文件名的 demo.js 文件 => 生成 js 文件后即可通过 node demo.js 去运行 js 文件

4. 主动编译执行 ts:

npm install -g ts-node
编译执行 ts-node demo.ts

三、根底语法

1. 编辑器提醒

let b = 123
b = '123'   不非法 不可能将‘string’赋值给‘number’let b:number = 123;  残缺的定义类型 
function tsMathDemo(data: {x:number,y:number}){return Math.sqrt(data.x**2 + data.y **2)
}
tsMathDemo()       提醒报错
tsMathDemo({x:3,y:4})    失常编译 

const count: number = 2019
count 就蕴含了所有 number 类型的办法 count. 编译器主动提醒

2. 另外两种定义参数类型办法(类型别名)

type Point = {x: number,y: number}
interface Point{x: number,y: number}
function tsFunc(data: Point){return}
// 用法
interface Point {
  x: number
  y: number
}
const point: Point = {
  x: 3,
  y: 5
}

3. 根底类型:number string null undefined symbol boolean void

const count: number = 123
const teacherName: string = 'Nico'

4. 对象类型

const teacher: {
  name: string
  age: number
} = {
  name: 'Dell',
  age: 8
}
const numbers: number[] = [1, 2, 3]

5. 类

class Person {}
const dell: Person = new Person()

6. 函数

const getTotal: () => number = () => {return 123}

7. 类型注解 type annotation 显示申明类型,通知 ts 变量是什么类型

let count: number
count = 123

8. 类型推断 type inference ts 主动尝试剖析变量的类型

let countInference = 123
// 类型推断 func
const func = (str: string) => {return parseInt(str, 10)
}
// 类型注解 func1
const func1: (str: string) => number = (str) => {return parseInt(str, 10)
}
const date = new Date()

9. 参数须要应用类型注解申明,防止调用时传参类型不对

function getTotal(firstNumber: number, secondeNumber: number) {return firstNumber + secondeNumber}
const total = getTotal(1, 2)

10. 定义函数

function hello() {}
const hello1 = function () {}
const hello2 = () => {}
function add(first: number, second: number): number {return first + second}
// 不能有返回值
function sayHello(): void {console.log('hello')
}
// never 永远不可能执行实现
function errorEmitter(): never{throw new Error()
  console.log(123)
}
// 形参类型为解构赋值时的类型注解写法
function add({first, second}: {first: number; second: number}): number {return first + second}
const total = add({first: 1, second: 2})

11. 联结类型

let temp: number | string = 123
temp = '456'

12. 数组

const arr: (number | string)[] = ['1', 2, 3]

13.type alias 类型别名

type User = {name: string; age: number}
const objectArr: User[] = [{ name: 'dell', age: 12}]
class Teacher {
  name: string
  age: number
}
const objectArr2: Teacher[] = [new Teacher(), {name: 'bell', age: 14}]

14. 元组 tuple : 按程序限度类型

const teacherInfo: [string, string, number] = ['xxx', 'yyy', 2]
//csv
const teacherList: [string, string, number][] = [['dell', 'male', 2],
  ['dell', 'male', 2],
  ['dell', 'male', 2]
]

15. 定义接口

interface Person {
  name: string
  age?: number // age 可有可无,不肯定要有值
  readonly tall: number // tall 为只读,不可赋值
  [propName: string]: any // 还能够有其余属性。属性名称类型为 string, 值能够为任意类型
  say(): string // 得有一个 say() 办法,返回值为 string
}
// 利用接口
class User implements Person {
  name = 'dell'
  tall = 170
  say() {return 'say hello'}
  sex = 'female'
}
// 接口继承
interface Teacher extends Person {teach(): string
}

16. 接口申明函数类型

interface SayHi {(word: string): string
}
const say: SayHi = (word: string) => {return word}

17. 定义类

class Person {
  name = 'dell'
  getName() {return this.name}
}
// 继承类
class Teacher extends Person {getTeacherName() {return 'teacherName'}
  getName() {return super.getName() + 'lee'; // 笼罩父类的 getName,应用 super 对象调用父类被笼罩的办法
  }
}
class Person {
// 传统写法
  public name: string;
  constructor(name: string){this.name = name}
// 简化写法
  constructor(public name: string) {}}

18. 继承类

class Person {constructor(public name: string){}}
class Teacher extends Person {constructor(public age: number){super('name')
  }
}
const teacher = new Teacher(28)

19.getter 和 setter

class Person {constructor(private _name: string) {}
  get name() {return this._name}
  set name(name: string) {this._name = name}
}
const person = new Person('dell')
console.log(person.name)
person.name = 'dell_lee'   // 'dell_lee'

20. 单例模式

class Demo {
  private static instance: Demo
  private constructor(public name: string) {} // 结构器设计为 private,那么就不能间接在内部 new Demo() 去创立实例
  static getInstance(name: string) {
  //static 将办法间接挂载在类下面,而不是挂载在类的实例上
  if (!this.instance) {this.instance = new Demo(name)
  }
  return this.instance
  }
}
const demo1 = Demo.getInstance('dell') // 实际上 demo1 === demo2 了
const demo2 = Demo.getInstance('nick') // 实际上 demo1 === demo2 了
console.log(demo1.name) // dell
console.log(demo2.name) // dell

21. 抽象类

abstract class Geom {abstract getArea(): number
}
class Circle extends Geom {getArea() {return 123}
}
class triangle extends Geom{}   // 没实现抽象类中的 getArea() 编辑器会报错
class square {}

四、ts 配置等内容

1. 代码扭转时主动编译代码到 build 目录下

"build": "tsc -w"  //package.json 配置启动命令 
"outDir": "./build"  // tsconfig.json 配置 

2. 在文件发生变化的时候就会主动执行 build 目录下的 crowller.js 文件

npm i nodemon -D    // 检测整个我的项目下的文件变动,而后去做绝对应的动作。
"start": "nodemon node ./build/crowller.js"    //package.json 配置启动命令 

主动疏忽 data 文件下的所有文件变动。防止造成循环调用 start 命令。

"nodemonConfig": {    //package.json 配置项
  "ignore": ["data/*"]
},

联合下面的 build 命令,那么通过批改文件,就会主动编译生成 js 文件,再通过 nodemon 去监测文件的变动主动执行相应的操作

3. 同时执行多条命令,解决以上的 build 以及 nodemon 命令须要别离开一个终端能力执行。

npm i concurrently -D
"scripts": {    //package.json 配置
  "dev:build": "tsc -w",
  "dev:start": "nodemon node ./build/crowller.js",
  "dev": "concurrently npm:dev:*"
},

将 package.json 中的 scripts 命令配置成这样,npm:dev:* 会泛匹配执行所有名为 dev:build、dev:start 等命令

4.npm 参数 - D 和 - S 的区别

–save-dev(也就是 -D) 装置的 插件,被写入到 devDependencies 对象外面去;而应用 –save(-S) 装置的插件,则被写入到 dependencies 对象外面去。
devDependencies 外面的插件只用于开发环境,不用于生产环境,而 dependencies 是须要公布到生产环境的。

5.tsConfig.json 文件配置

<1> 指定只编译或者不编译的文件:

"include": ["./demo.ts"],
"exclude": ["./demo.ts"],

<2> 增量编译,只编译较上次更新的内容:

"incremental": true,

<3> 容许 JS 文件也能够编译:

"allowJs": true,

<4> 把所有要输入的文件,放到一个文件里去

"outFile": "./",

更多配置查阅 ts 官网 documents 选项中的 tsconfig.json


五、爬虫

npm init -y 生成 package.json
tsc -init 生成 tsconfig.json
npm install -D ts-node (- D 相当于 –save-dev 装置在我的项目 dev 中)
配置 src 目录及爬虫文件 配置 dev 命令

npm install superagent –save 发申请取得数据
npm install @types/superagent -D 翻译文件使 ts 能解析 superagent 依赖包

npm install cheerio -D 提取数据的依赖
npm install @types/cheerio -D 翻译文件

node 外围模块 fs、path 判断和读写文件

函数职责明确 尽量 return 返回值,再去获取返回值传给下一个须要调用的函数


六、ts 高级语法

1. 联结类型和类型爱护

<1> 类型爱护之类型断言

interface Bird {
  fly: boolean;
  sing: () => {};
}
interface Dog {
  fly: boolean;
  bark: () => {};
}
function trainAnial(animal: Bird | Dog) {if (animal.fly) {(animal as Bird).sing();} else {(animal as Dog).bark();}
}

<2> 类型爱护之 in 语法

function trainAnial(animal: Bird | Dog) {if('sing' in animal){animal.sing();
  }else{animal.bark();
  }
}

<3> 类型爱护之 typeof

function add(first: string | number,second: string | number){if(typeof first === 'string' || typeof second === 'string'){return ${first}${second}
  }
  return first + second
}

<4> 类型爱护之 instanceof

class NumberObj {count: number;}
function addSecond(first: object | NumberObj, second: object | NumberObj) {if (first instanceof NumberObj && second instanceof NumberObj) {return first.count + second.count;}
  return 0;
}

2. 枚举类型

// 枚举类步长为 1, 默认 0 开始
enum Status {
  OFFLINE, //0
  ONLINE, //1
  DELETED, //2
}
console.log(Status[1]); // ONLINE
console.log(Status.OFFLINE); // 0
function getResult(status: number) {if (status === Status.OFFLINE) {return "offline";} else if (status === Status.ONLINE) {return "online";} else if (status === Status.DELETED) {return "deleted";}
  return "error";
}
getResult(Status.ONLINE); // online

3. 函数泛型

//  泛型 generic 泛指的类型
function join

4. 类的泛型以及泛型类型

<1> 类的泛型根底用法

class DataManager<T> {constructor(private data: T[]) {}
  getItem(index: number): T {return this.data[index];
  }
}
const data = new DataManager<string>(["1"]);
console.log(data.getItem(0));

<2> 泛型继承 inteface

interface Item {name: string;}

class DataManager<T extends Item> {constructor(private data: T[]) {}
  getItem(index: number): string {return this.data[index].name;
  }
}
const data = new DataManager([{name: "dell"}]);
const res = data.getItem(0);

<3> 类的泛型束缚

class DataManager<T extends number | string> {constructor(private data: T[]) {}
  getItem(index: number): T {return this.data[index];
  }
}
interface Test {name: string;}
// const data = new DataManager<Test>([]); // 报错,类型“Test”不满足束缚“string | number”const data = new DataManager<number>([1]);
console.log(data.getItem(0));

<4> 如何应用泛型作为一个具体的类型注解

// 如何应用泛型作为一个具体的类型注解
function hello<T>(params: T) {return params;}
const func: <T>(params: T) => T = hello;

4.namespce 命名空间

<1> 这会生成四个全局变量,但实际上只须要生成一个 Page 变量即可

class Header {constructor() {const elem = document.createElement("div");
    elem.innerText = "This is Header";
    document.body.appendChild(elem);
  }
}

class Content {constructor() {const elem = document.createElement("div");
    elem.innerText = "This is Content";
    document.body.appendChild(elem);
  }
}

class Footer {constructor() {const elem = document.createElement("div");
    elem.innerText = "This is Footer";
    document.body.appendChild(elem);
  }
}

class Page {constructor() {new Header();
    new Content();
    new Footer();}
}

用 namespace 能够躲避过多产生不必要的全局变量, 编译后只产生命名空间 Home 这一个全局变量:

namespace Home {
  class Header {constructor() {const elem = document.createElement("div");
      elem.innerText = "This is Header";
      document.body.appendChild(elem);
    }
  }

  class Content {constructor() {const elem = document.createElement("div");
      elem.innerText = "This is Content";
      document.body.appendChild(elem);
    }
  }

  class Footer {constructor() {const elem = document.createElement("div");
      elem.innerText = "This is Footer";
      document.body.appendChild(elem);
    }
  }

  export class Page {constructor() {new Header();
      new Content();
      new Footer();}
  }
}
<body>
  <script src="./dist/page.js"></script>
  <script>
    new Home.Page()
  </script>
</body>

<2> 模块化命名空间

tsconfig.json 配置,将所有文件打包输入到一个文件内,使命名空间之间能够相互调用(能够查看编译过后的 js 文件,变量都在一个文件内申明,能够相互拜访):

"module": "amd",
"outFile": "./dist/page.js",

次要调用的命名空间文件 page.ts

///<reference path='./components.ts' />
// 应用 reference 申明以后命名空间援用的其它命名空间,不便后续浏览代码
namespace Home {
  export class Page {user: Components.user = { name: "dell"}; // 援用其它命名空间的接口 interface
    constructor() {new Components.Header();
      new Components.Content();
      new Components.Footer();}
  }
}

提取进去的命名空间文件 components.ts

namespace Components {
  export namespace SubComponents {
    // 子命名空间,能够再控制台通过 Components.SubComponents.Test 拜访到子命名空间抛出来的内容
    export class Test {}}

  export interface user {name: string;}

  export class Header {constructor() {const elem = document.createElement("div");
      elem.innerText = "This is Header";
      document.body.appendChild(elem);
    }
  }

  export class Content {constructor() {const elem = document.createElement("div");
      elem.innerText = "This is Content";
      document.body.appendChild(elem);
    }
  }

  export class Footer {constructor() {const elem = document.createElement("div");
      elem.innerText = "This is Footer";
      document.body.appendChild(elem);
    }
  }
}

index.html 文件:

<body>
  <script src="./dist/page.js"></script>
  <script>
    new Home.Page()
  </script>
</body>

5.parcel 打包

官网文档:github.com/parcel-bundler/parcel;
装置:npm i parcel@next -D;
package.json 配置 scripts 命令:

"start": "parcel ./src/index.html"    // 运行该命令就会启动一个服务器 

6. 形容文件中的全局类型

index.html 引入 jQuery:https://cdn.bootcss.com/jquer…
失常状况下 ts 不会解析 jQuery 语法,须要装置形容文件:

npm i @types/jquery

本人试着手写解析 $ 选择器的类型形容文件:

<1>page.ts 内容:

// 第一种
$(function () {alert("123");
});
// 第二种
$(function () {$("body").html("<div>123fsa</div>");
});
// 第三种
$(function () {new $.fn.init();
});

<2>jquery.d.ts 类型形容文件:

// 办法一
// declare 定义全局变量 $, 接管的参数为一个函数,返回值为空 void。// declare var $: (param: () => void) => void;

// 办法二
//declare 定义全局函数;interface JqueryInstance {html: (html: string) => JqueryInstance;
}
declare function $(readyFunc: () => void): void;    // 第一种
declare function $(selector: string): JqueryInstance;    // 第二种
declare namespace $ {    // 第三种,对对象进行类型定义,以及对类进行类型定义,以及命名空间的嵌套
  namespace fn {class init {}    // 因为是 new $.fn.init(),所以 init() 是一个构造函数,所以应用 class 去定义 init()}
}

<3>jquery.d.ts 类型形容文件的优化版本:

// 应用 interface 接口申明函数类型的语法,实现函数重载
interface JqueryInstance {html: (html: string) => JqueryInstance;
}
interface JQuery {(readyFunc: () => void): void;
  (selector: string): JqueryInstance;
}
declare var $: JQuery;// 应用 interface 接口申明函数类型的语法,实现函数重载
interface JqueryInstance {html: (html: string) => JqueryInstance;
}
interface JQuery {(readyFunc: () => void): void;
  (selector: string): JqueryInstance;
}
declare var $: JQuery;

<4>ES6 模块化的类型形容文件写法:

将 script 引入 cdn 门路办法改成:npm i jquery –save 装置,而后应用 import 导入

import $ from 'jquery'
$(function () {$("body").html("<div>123fsa</div>");
  new $.fn.init();});
//Es6 模块化
declare module "jquery" {    // 定义的 module 名称要与 import 的统一
  interface JqueryInstance {html: (html: string) => JqueryInstance;
  }
  // 混合类型
  function $(readyFunc: () => void): void;
  function $(selector: string): JqueryInstance;
  namespace $ {
    namespace fn {class init {}
    }
  }
  export = $;    // 导出 $
}

七、

退出移动版