本文主要讲述静态类型、类型注解、类型推断、泛型、类型定义文件、模块化、打包编译、装饰器、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 = $; // 导出$
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。