Typescript第九/十章 前后端框架,命名空间和模块

第九章 前后端框架

9.1 前端框架

Typescript特别适合用于开发前端应用。Typescript对JSX有很好的支持,而且能安全地建模不可变性,从而提升应用的结构和安全性,写出的代码正确性高,便于维护。

9.1.1 React

JSX/TSX内容等

详情请到React官方学习

9.1.2 Angular

详情请到Angular学习

依赖注入,控制反转

9.1.3 Vue

详情请到Vue官方学习

Vue3全面支持Typescript

9.2 类型安全的API

  • 针对REST式API的swagger
  • 针对GraphQI的Apollo
  • 针对RPC的gRPC

9.3 后端框架

Nest.js完全支持Typescript

通过Typescript访问数据库,TypeORM超好用

第十章 命名空间和模块

在一个程序中,我们可以在不同的层级上进行封装。在最底层,函数封装行为,对象和列表等数据结构封装数据。函数和数据还可以放在类中,还可以把函数放在单独的数据库或数据存储器中,把函数和数据放入独立的命名空间中。

通常一个类或一系列使用函数放在一个文件中。再向上一层,我们可能会把多个类或多组使用函数组织在一起,构建成包(package),发布到NPM中。

模块(module)是一个重要概念,

我们要知道编译器(TSC)是如何解析模块的,

要知道构建系统(Webpack,Gulp,Vite等)是如何解析模块的,

还要知道模块在运行时是如何加载到应用的(使用<script/>标签,SystemJS等)。

对JavaScript来说,这些操作往往都由单独的程序执行,有点混乱。CommonJS和ES2015模块标准简化了这三个程序之间的互操作,Webpack等强大的打包程序进一步抽象了这三个解析过程背后涉及的操作。

本章着重讨论这这三种工具中的第一种,即Typescript解析和编译模块所用的工具,第12章再讨论构建系统和运行时加载程序。

  • 实现命名空间和模块的不同方式
  • 导入和导出代码的不同方式
  • 在代码增长的过程中弹性伸缩这些方法。
  • 模块模式与脚本模式的比较
  • 声明合并的概念及其作用

10.1 JavaScript模块简史

由于Typescript最终编译成JavaScript,并与JavaScript互操作,因此Typescript要支持JavaScript程序使用的各种模块标准。

起初(1995)JavaScript并不支持任何模块系统。由于没有模块,一切都在全局命名空间中声明,导致应用非常难以构建和弹性伸缩。而且,我们无法显式指明各个模块对外开放哪些API。

为了解析问题,人们通过对象或理解调用函数(IIFE)表达式模拟模块,把对象或IIFE附加到全局对象window上,供当前应用

 window.emailListmModule = {renderList(){}}window.emailComposerModule = {renderComposer(){}}window.appModule = {renderApp(){window.emailListmModule.renderList()window.emailComposerModule.renderComposer()}}

可是加载和运行JavaScript会阻塞浏览器UI,浏览器会变得越来越慢。

于是有了新方案:在页面加载完成之后动态加载JavaScript,而不同时加载。

在页面加载完毕之后惰性(通常是异步)加载JavaScript代码,为了实现异步惰性,需要做到以下三点:

  1. 模块要适当的封装,否则,不断流入的依赖会导致页面崩溃
  2. 模块之间的依赖要显示声明,否则,不知道需要加载什么模块,以及以什么顺序加载。
  3. 每个模块在应用中都要有一个唯一标识符。否则,无法指定需要加载哪个模块。

nodejs大哥采用用的是Commonjs模块标准

 // emailBaseModule.jslet emailList = require('emailListModule')let emailComposer = require("emailComposerModule")module.exports.renderBase = function(){}

可是Commjs处理事情的方式有几个问题,包括:require必须同步调用,Commonjs模块解析算法不适合在web使用。Commjs的代码在某些情况下不会做静态分析。

因为module.exports可能出现在任何位置(甚至可能在不会执行的分支),require调用可以出现任何位置,而且可以包含任意字符串和表达式,就导致静态链接JavaScript,不能确认被 引用的文件真实存在,也无法确保被引用的文件真正的到处了声称的代码。

然后,ECMAScript语言第六版,即ES2015为导入和导出引入了一个新标准,句法更简洁,而且支持静态分析。

 // emailBaseModule.jsimport emailList from 'emialListModule'import emailComposer from 'emailCpmposerModule'export function rederBase(){}

如今,我们在JavaScript和Typescript中使用的就是这个标准。不是每个JavaScript引擎都原生支持这个标准,所以要把代码编译成被支持的格式(在nodejs中编译成commonjs格式,在浏览器环境中,编译成全局或单个模块可加载的格式)

TSC的构建系统还支持针对不同的目标环境编译模块,包括:全局,ES2015,Commonjs,AMD,Systemjs,UMD。

10.2 import,export

除非迫不得已,不要在Typescript中使用Commjs,全局或命名空间下的模块。

 // a.tsexport function foo(){}export function bar(){}​import {foo,bar} from './a'​export let result = bar()
 // ./c.tsexport default function meow(){}import meow form './c'meow()
 import * as a from './a'​a.foo()
 export * from './a'export {result} from './b'export meow from './'

由于我们编写的是Typescript,而不是JavaScript代码,所以,除了值外,还可以导出类型和接口。因为类型和值位于不同的命名空间中,所以可以导出两个同名的内容,一个在值层面,一个在类型层面。Typescript将推导出你值得是类型还是值

 // g.tsexport let X = 3;export type X = {y:string}​// h.tsimport {X} from './g'​let a = X + 1let b:X = {y:'z'}

10.2.1 动态导入

应用变大后,初次渲染的时间将不断增加。这对前端应用来说是不可忽视的问题。

进一步的优化措施是惰性加载分块,在真正使用的时候才加载。

LABjs及其衍生库引入了真正需要时才惰性加载的概念,这个概念正式的名称是“动态导入”(dynamic imports),用法

 let locale = awat import('locale_cn-en')

import可以作为一个语句使用,作用是静态获取代码,另外,也可以作为一个函数调用,此时返回结果是一个Promise

动态导入应该使用下面两种做法中的其中一种:

  1. 直接把字符串字面量传给import,不要事先赋值给变量
  2. 把表达式传给import,但要手动注解模块的签名
 import {locale} form ''async function main(){let userlocal = awat getuserlocal()let path = "./loca-${userlocal}"let local:typeof locale = await import(path)}

导入locale不过只作为类型,这样写出代码不仅具有十足的类型安全,而且能动态计算导入那个包。

10.2.2使用Commonjs和AMD模块

使用Commjs或AMD标准的JavaScript模块时,可以直接从模块中导入名称,就像使用es2015模块一样

 import {something} from './commonjs/module'

默认情况下,commonjs的默认导出不能与es2015的默认导出互操作:使用默认 导出,要借助通配符:

 import * as fs from 'fs'fs.readFile('some/file.txt')​// import { readFile } from "fs";​// readFile​// import * as fs from 'fs'// fs.readFile

10.2.3 模块模式与脚本模式

Typescript采用两种模式编译Typescript文件:模块模式和脚本模式,

文件中有没有import或export语句,如果有使用模块模式,如果没有,使用脚本模式

目前为止我们使用的都是模块模式,

在脚本模式下,声明的顶层变量子啊项目中的任何文件都可以使用,无需导入,可以放心使用UMD模块中的全局导出,不用事先导入,下述情况使用脚本模式:

  1. 快速验证不打算编译成任何模块系统的浏览器代码({“module”:”none”}),在html文件中直接使用<script/>标签引入
  2. 创建类型声明(11.1节)

其实,在使用Typescript编写代码时,基本上应该始终使用模块模式,通过import导入代码,通过export导出代码,供其他文件使用。

10.3 命名空间

Typescript还提供了另一种封装代码的方式:namespace关键字。很多java,C#,C++,PHP和python都支持。

要注意一点:虽然Typescript支持命名空间,但这并不是封装代码的首选方式。如果你不确定使用命名空间还是模块,首选模块!

命名空间所做的抽象摒弃了文件在文件系统中的目录结构,我们无需知道.mine函数保存在a/b/c/d中,若想使用这个函数,使用简洁的命名空间A.B.C.D.mine即可

假设有两个文件,一个文件是发起http get请求的模块,另一个文件使用该模块发起请求:

 // Get.tsnamespace Network {export function get<T>(url: string): Promise<T> {return new Promise(()=>{})}}// App.tsnamespace App {Network.get<GitRepo>("api.github.com/repos/")}

命名空间必须有名称,命名空间可以导出函数,变量,类型,接口和其他命名空间。namespacekuai中没有显示导出的代码为所在块的私有代码。由于命名空间可以导出命名空间,因此命名空间可以嵌套。

 namespace Netwok {export namespace HTTP {export function get<T>(url:string):Promise<T>{return new Promise(()=>{})}   }export namespace TCP{export function listenerCount(port:number){​}function test(){​}}export namespace UDP{​}}Netwok.HTTP.getNetwok.TCP.listenerCountNetwok.TCP.test // 找不到

命名空间也可以分散在多个文件中。Typescript将递归合并名称相同的命名空间

为了使用方便,可以创建别名

 namespace A {export namespace B{export namespace C {export let d = 3}}}import d = A.B.C.dlet e = d*3console.log(e);//9

10.3.1 冲突

导出相同名称的代码会导致冲突:

 // 报错namespace Network {export function request(){}}namespace Network {export function request(){}}​

特例,改进函数类型时对外参(ambient)函数声明的重载不导致冲突

10.3.2 编译输出

与导入和导出不一样,命名空间不遵循tsconfig.json中的module设置,始终编译成全局变量。

模块优于命名空间

为了更符合JavaScript标准,为了更明确地指定依赖,较之命名空间,应该更多的使用常规的模块

明确指明依赖的好处很多,可以提示代码可读性,可以强制模块隔离,还可以做静态分析。

在大型项目中,建议全部使用模块,不要用命名空间

10.4 声明合并

目前,我们接触到了Typescript所做的三种合并:

  • 合并值和类型,根据使用情况区分一个名称是引用值还是类型
  • 把多个命名空间合并成一个
  • 把多个接口合并成一个

Typescript支持很多类型的合并,让一些难以表达的模式变为可能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/20335.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

c语言实现八大排序详细解析

首先先看排序算法的整体分类 排序&#xff1a;所谓排序&#xff0c;就是使一串记录&#xff0c;按照其中的某个或某些关键字的大小&#xff0c;递增或递减的排列起来的操作。 稳定性&#xff1a;假定在待排序的记录序列中&#xff0c;存在多个具有相同的关键字的记录&#xff…

为Android构建现代应用——应用导航设计

在前一章节的实现中&#xff0c;Skeleton: Main structure&#xff0c;我们留下了几个 Jetpack 架构组件&#xff0c;这些组件将在本章中使用&#xff0c;例如 Composables、ViewModels、Navigation 和 Hilt。此外&#xff0c;我们还通过 Scaffold 集成了 TopAppBar 和 BottomA…

yolov3-spp 训练结果分析:网络结果可解释性、漏检误检分析

1. valid漏检误检分析 ①为了探查第二层反向找出来的目标特征在最后一层detector上的意义&#xff01;——为什么最后依然可以框出来目标&#xff0c;且mAP还不错的&#xff1f; ②如何进一步提升和改进这个数据的效果&#xff1f;可以有哪些优化数据和改进的地方&#xff1f;让…

《ChatGPT原理最佳解释,从根上理解ChatGPT》

【热点】 2022年11月30日&#xff0c;OpenAI发布ChatGPT&#xff08;全名&#xff1a;Chat Generative Pre-trained Transformer&#xff09;&#xff0c; 即聊天机器人程序 &#xff0c;开启AIGC的研究热潮。 ChatGPT是人工智能技术驱动的自然语言处理工具&#xff0c;它能够…

竞争之王CEO商战课,聚百家企业在京举行

竞争之王CEO商战课&#xff0c;于2023年7月29-31日在北京临空皇冠假日酒店举办&#xff0c;近百家位企业家齐聚一堂&#xff0c;共享饕餮盛宴。 竞争之王CEO商战课是打赢商战的第一课。 竞争环境不是匀速变化&#xff0c;而是加速变化。 在未来的市场环境中&#xff0c;企业间…

Day12-1-Webpack前端工程化开发

Webpack前端工程化 1 案例-webpack打包js文件 1 在index.html中编写代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><me…

基于Kubernetes环境的高扩展机器学习部署利器——KServe

随着ChatGPT的发布&#xff0c;人们越来越难以回避利用机器学习的相关技术。从消息应用程序上的文本预测到智能门铃上的面部识别&#xff0c;机器学习&#xff08;ML&#xff09;几乎可以在我们今天使用的每一项技术中找到。 如何将机器学习技术交付给消费者是企业在开发过程中…

【Spring Boot】请求参数传json数组,后端采用(pojo)新增案例(103)

请求参数传json数组&#xff0c;后端采用&#xff08;pojo&#xff09;接收的前提条件&#xff1a; 1.pom.xml文件加入坐标依赖&#xff1a;jackson-databind 2.Spring Boot 的启动类加注解&#xff1a;EnableWebMvc 3.Spring Boot 的Controller接受参数采用&#xff1a;Reque…

构建vue项目配置和环境配置

目录 1、环境变量process.env配置2、vue package.json多环境配置vue-cli-service serve其他用法vue-cli-service build其他用法vue-cli-service inspect其他用法3、vue导出webpack配置4、配置打包压缩图片文件5、打包去掉多余css(由于依赖问题暂时未实现)6、打包去除console.…

【Linux】进程间通信——管道

目录 写在前面的话 什么是进程间通信 为什么要进行进程间通信 进程间通信的本质理解 进程间通信的方式 管道 System V IPC POSIX IPC 管道 什么是管道 匿名管道 什么是匿名管道 匿名管道通信的原理 pipe()的使用 匿名管道通信的特点 拓展代码 命名管道 什么是命…

IDEA离线环境搭建远程开发-Windows

公司的云桌面实在太卡&#xff0c;多个微服务项目跑起来&#xff0c;直接无法进行其它编码工作&#xff0c;所以想到使用Idea提供的远程开发功能&#xff0c;将服务运行在服务器&#xff0c;电脑只提供给开发页面展示&#xff0c;提高效率。 环境介绍&#xff1a; 开发环境&…

SystemVerilog数组参数传递及引用方法总结

一、将常数数组传递给task/function 如下面的程序&#xff0c;将一个常数数组传递给function module my_array_test();function array_test(int array[4]);foreach(array[i]) begin$display("array[%0d] %0d", i, array[i]);endendfunctioninitial beginarray_tes…

景联文科技高质量成品数据集上新啦!

景联文科技近期上新多个成品数据集&#xff0c;包含图像、视频等多种类型的数据&#xff0c;涵盖丰富的场景&#xff0c;可满足不同模型的多元化需求。 高质量成品数据集可用于训练和优化模型&#xff0c;使得模型能够更加全面和精准地理解和处理任务&#xff0c;更好地应对复…

anaconda创建虚拟环境在D盘

【看一看就行&#xff0c;又是挺水的一期&#xff08;每一季都掺和一点子水分也挺好&#xff09;】 一、创建&#xff1a; conda create --prefixD:\python37\py37 python3.7 这下就在D盘了&#xff1a; 二、激活刚刚那个环境&#xff1a; activate D:\pyhton37\py37​ &…

python sqllite基本操作

以下是一些基本的SQLite3操作&#xff1a; 连接到数据库&#xff1a;使用sqlite3.connect()函数连接到数据库&#xff0c;返回一个Connection对象&#xff0c;我们就是通过这个对象与数据库进行交互。例如&#xff1a; import sqlite3 conn sqlite3.connect(example.db)创建…

​LeetCode解法汇总722. 删除注释

目录链接&#xff1a; 力扣编程题-解法汇总_分享记录-CSDN博客 GitHub同步刷题项目&#xff1a; https://github.com/September26/java-algorithms 原题链接&#xff1a;力扣 描述&#xff1a; 给一个 C 程序&#xff0c;删除程序中的注释。这个程序source是一个数组&#x…

如何微调医疗大模型llm:llama2学习笔记

三个微调方向&#xff1a;简单医疗问答 临床问答 影像学 一般流程&#xff1a; 1 数据集准备 2 模型基座选择 3 微调 4 案例拆解 1 数据集准备&#xff1a;两种类型&#xff0c;一种文本一种影像 扩展&#xff0c;多模态 2 模型基座选择 多模态处理所有视频&#xff0c;文本…

连接 MySQL

文章目录 1.连接本地 MySQL2.连接远程 MySQL3.退出 MySQL4.查看 MySQL 版本 1.连接本地 MySQL 首先打开 Shell 命令终端或命令行程序&#xff0c;键入命令mysql -u root -p&#xff0c;回车后提示输入密码。注意用户名和密码与命令选项之间的空格可有可无。 mysql -u USER_NA…

【汇总】解决Ajax请求后端接口,返回ModelAndView页面不跳转

【汇总】解决Ajax请求后端接口&#xff0c;返回ModelAndView不跳转 问题发现问题解决方法一&#xff1a;直接跳转到指定URL&#xff08;推荐&#xff09;方法二&#xff1a;将返回的html内容&#xff0c;插入到页面某个元素中方法三&#xff1a;操作文档流方法四&#xff1a;使…

leetcode做题笔记51

按照国际象棋的规则&#xff0c;皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。 n 皇后问题 研究的是如何将 n 个皇后放置在 nn 的棋盘上&#xff0c;并且使皇后彼此之间不能相互攻击。 给你一个整数 n &#xff0c;返回所有不同的 n 皇后问题 的解决方案。 每一种…