TypeScript学习笔记(一) 概述

大家好,我是半虹,这篇文章介绍 TypeScript 中的一些基础概念


1、概述

TypeScript 是由微软开发的一门编程语言,可以看作是 JavaScript 的超集,具有 JavaScript 的所有特性

同时,其在 JavaScript 基础上增加新特性,拓展 JavaScript 的功能,使其能适用于任何规模的项目场景


其中最重要的特性就是添加静态类型,使得开发者可以在开发阶段显式地声明变量类型

不仅使得代码更加清晰可读,而且能在编译阶段进行类型检查,帮助捕获潜在类型错误


了解 JavaScript 的朋友应该清楚, JavaScript 在遇到意外情况时会尽可能继续运行下去

举个例子:

// JavaScript

function add(a, b) {
  return a + b
}

假设这里我们定义一个加法函数,接收两个数字作为参数,返回两个数字相加之和

但在实际调用时,因为某些原因,其中的第二个参数错误地收到一个数组

let p1 = 3
let p2 = [1, 2]

add(p1, p2)

因为 JavaScript 的隐式类型转换,所以函数还是正常执行,不会产生错误

并且得到一个意料之外的返回值:字符串 31,2

后续程序将会以不可知的状态继续运行着,并且这个错误也可能继续传递

导致最终显现出来的错误难以排查解决


而这一切都可以通过静态类型彻底解决,使其在编译阶段就暴露出来问题

对应代码如下:

// TypeScript

function add(a:number, b:number):number { // 显式声明函数接收两个数字作为参数,同时返回一个数字作为结果
  return a + b
}

let p1:number = 3        // 显式声明变量类型为数字
let p2:number[] = [1, 2] // 显式声明变量类型为数组
  
add(p1, p2) // ERROR,函数形参与传入实参类型无法匹配

这段 TypeScript 代码与上述 JavaScript 代码所实现的功能逻辑完全一致

唯一的不同在于 TypeScript 代码在定义变量或函数时可以显式声明类型,具体来说:

  • 定义变量时,写法为:name:type ,如上述 p1p2
  • 定义函数时,写法为:function name(para1:type1, ...):return_type {...},如上述 add

这样调用函数时,就能根据声明的类型判断变量的赋值类型是否正确

这种定义变量时指定类型的写法,相信熟悉 C 或者 JAVA 等静态语言的朋友不会感到陌生


这里还想提醒下,TypeScript 中的类型声明不是必须要的

因为就算没有显式声明,程序本身也会隐式推断,如下例

let foo = 123

这里我们没有声明类型,但是程序也能根据初始赋值推断变量的类型为 number

正因为如此,任何有效的 JavaScript 代码也是有效的  TypeScript  代码


静态类型的引入给  TypeScript  带来了很多的优点

  1. 静态分析:无需实际运行代码,即可推断是否存在类型错误,避免运行时出现相关的异常
  2. 代码提示:开发工具借由类型,能够提供更智能的代码提示与自动补全

但是与此同时,静态类型的使用也存在着一些缺点

  1. 增加复杂性:静态类型上手难度更高,代码编写更为繁琐复杂
  2. 增加工作量:正常编写功能代码之外,还需额外声明变量类型,带来更多的工作量

综合来看,TypeScript 并非银弹,需要根据具体场景决定是否使用

通常来说,TypeScript 适合用于:需要长期维护的大规模团队项目


2、安装与使用

TypeScript 的执行过程与其他语言有很大的不同,因为该语言没有提供对应的运行环境

因此,TypeScript 总是先转换成 JavaScript, 再借助 JavaScript 的运行环境去执行代码【重要】

上述的转换过程由官方所发布的编译器完成,该编译器称为 TypeScript Compiler (tsc)


可以通过以下命令安装 tsc 模块

npm install -g typescript

随后通过以下命令查看 tsc 版本,检查安装是否成功

tsc -v

如果一切正常,现在就可以使用 tsc 将 TypeScript 编译成 JavaScript

TypeScript 程序文件的后缀名是 .ts ,tsc 能将其转换成 JavaScript 程序文件,后缀名为 .js

下面我们来创建一个 TypeScript 文件 index.ts,并写入之前的代码

function add(a:number, b:number):number {
  return a + b
}

let p1:number = 3
let p2:number[] = [1, 2]
  
add(p1, p2) // ERROR

然后尝试去编译这个文件

tsc index.ts

这个时候,编译器实际上做了两件事情:

  1. 进行类型检查,如果发现类型问题就会产生错误提示
  2. 生成编译产物,将下一代 TypeScript / JavaScript 转换成能够运行在目标运行时的 JavaScript

需要注意,上述两个事情完全是独立的,这一点十分重要

换句话说,即使类型检查不通过,编译过程有报错,依然会生成编译产物


TypeScript 的代码可以看作是由两部分组成,分别是值代码以及类型代码

TypeScript 编译成 JavaScript 的一部分工作,就是删除所有类型相关代码

let x:number = 1;

例如上面这行代码,对于变量 x,类型为 number,对应的值是 1

如果要转换成 JavaScript 代码,则只会保留值部分,具体如下:

let x = 1;

这点非常重要,这是理解 TypeScript 的关键,我们也会在该系列后续文章中多次提到

现在只需记住,在 TypeScript 中,类型与值是分离的


我们回到开始的例子,看编译 index.ts  时究竟发生了啥

tsc index.ts

第一,进行类型检查,并发现 index.ts  中存在类型错误,从而产生报错如下:

index.ts:10:9 - error TS2345: Argument of type 'number[]' is not assignable to parameter of type 'number'.

第二,生成编译产物,会输出 index.ts  编译后的 JavaScript 文件 index.js

function add(a, b) {
    return a + b;
}
var p1 = 3;
var p2 = [1, 2];
add(p1, p2); // ERROR

这里我们使用最简单的命令行方式编译指定文件,在此基础上,其实还能添加多个编译参数

但在真实的项目场景下,这些参数通过不会放到命令行中指定,而是通过配置文件进行配置


TypeScript 编译配置文件通常命名tsconfig.json ,该文件所在目录作为项目的根目录

若想要使用 配置文件指导编译过程,有两种方法:

  1. 直接使用 tsc 命令,此时会从当前目录开始查找 tsconfig.json,并逐级往上搜索父目录
  2. 使用 tsc 命令,并且通过命令行参数 --project 指定一个包含有 tsconfig.json 的目录

TypeScript 编译配置文件标准结构为:

{
  ...,
  "compilerOptions": {
    ...
  }
}

具体可以分为两个部分,分别是 compilerOptions 之内的选项,和 compilerOptions 之外的选项


先看 compilerOptions 之外的选项,这些选项主要用于指定要编译的文件

选项 说明
files 用于指定一组编译文件路径,可以使用绝对路径或者相对路径
相对路径相对于项目根目录,也即 tsconfig.json 所在位置
文件路径支持用 glob 模式,如无显式指定拓展名,默认匹配 .ts.tsx.d.ts
include 用于指定一组编译文件路径,可以使用绝对路径或者相对路径,文件路径支持用 glob 模式
exclude 用于排除一组编译文件路径,这些文件将不会被编译

如果 filesinclude 同时被指定,那么这些文件都会同时包含进来

如果 filesinclude 都没被指定,那么默认编译当前目录和子目录下的 .ts.tsx.d.ts

exclude 可以用于排除 include 指定的文件 ,但对 files  指定的文件不产生影响

exclude 如果缺省填写,也会默认排除 node_modules 目录


再看 compilerOptions 之内的选项,这些选项主要用于设置各种编译参数

选项 说明
outDir 指定编译后的 JS 输出目录,这个目录会被编译器排除,除非使用 file 显式指定
target 指定编译后的 JS 目标版本,默认 es3,可选项有 es5es6 / es2015
module 指定编译后的 JS 模块系统,例如 commonjsamdumdes6 / es2015
lib 指定目标运行时 的库声明,例如 domes5es2015.promise
allowJs 是否允许编译 JS 脚本,如果为 true,那么除了 .ts.tsx.d.ts,还会编译 .js.jsx
checkJs 是否需要检查 JS 脚本,如果为 true,则会检查 JS 脚本是否存在类型错误
removeComments 删除编译后的 JS 脚本中的注释
declaration 是否生成类型声明文件 .d.ts,如果为 true,则在编译时自动生成
declarationDir 指定生成类型声明文件的输出目录 ,如无指定,则为文件的同级目录
rootDir 指定项目的根目录
outFile 指定编译文件打包到单个  JS  文件
typeRoots 默认情况下会引入  node_modules/@types  目录下的所有模块声明
如果显式指定 typeRoots ,那么只有指定的目录才会引入
types 默认情况下会引入 typeRoots 指定目录下的所有模块声明
如果显式指定 types , 那么只有指定的模块才会引入

由于编译选项很多,因此没办法在一篇文章中介绍完,更多编译选项,可以参考文档



好啦,本文到此结束,感谢您的阅读!

如果你觉得这篇文章有需要修改完善的地方,欢迎在评论区留下你宝贵的意见或者建议

如果你觉得这篇文章还不错的话,欢迎点赞、收藏、关注,你的支持是对我最大的鼓励 (/ω\)

相关推荐

  1. TypeScript学习笔记() 概述

    2024-04-26 03:02:01       14 阅读
  2. typescript学习笔记

    2024-04-26 03:02:01       30 阅读
  3. TypeScript 学习笔记

    2024-04-26 03:02:01       16 阅读
  4. TypeScript 学习笔记

    2024-04-26 03:02:01       16 阅读
  5. TypeScript 学习笔记

    2024-04-26 03:02:01       12 阅读
  6. Typescript学习笔记

    2024-04-26 03:02:01       14 阅读
  7. TypeScript 学习笔记

    2024-04-26 03:02:01       15 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-04-26 03:02:01       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-04-26 03:02:01       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-04-26 03:02:01       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-04-26 03:02:01       20 阅读

热门阅读

  1. 嵌入式学习57-ARM6(内核编译)

    2024-04-26 03:02:01       11 阅读
  2. vue 3 + TS 组合式标注类型

    2024-04-26 03:02:01       11 阅读
  3. leetcode152 乘积最大子数组

    2024-04-26 03:02:01       17 阅读
  4. Spark调优-解决job任务运行超时或者慢的问题

    2024-04-26 03:02:01       13 阅读
  5. SQLAlchemy 2.0 中文文档翻译完成

    2024-04-26 03:02:01       12 阅读
  6. uniapp 扫码功能

    2024-04-26 03:02:01       44 阅读
  7. 【prometheus学习过程】

    2024-04-26 03:02:01       18 阅读
  8. IntelliLock.Licensing.dll在VS中的16个使用方法

    2024-04-26 03:02:01       12 阅读
  9. 【Python】模拟windows文件名排序

    2024-04-26 03:02:01       12 阅读