TypeScript
学习笔记(一)
朋友们,本期内容是关于 TypeScript
的学习,如果您学习过 javaScript
,或 java
等后端语言,我认为您学习的过程将会非常轻松!本期内容包括类型和编译选项
,后续会继续更新!本期参考 TypeScript 中文手册
和 李立超老师
的讲解视频,特别鸣谢❤️!
文章目录
TypeScript 是什么?
TypeScript
是以javascript
为基础构建的语言TypeScript
是javascript
的超集,扩展了javascript
的语法,并添加了许多新的特性。TypeScript
可以再任何支持javascript
的平台中执行TypeScript
扩展了javascript
的语法,增加的功能包括类型推断、枚举、元组
等等。
如果你已经学习了
javascript
就能够快速上手typescript
!
TypeScript 能直接代替 JavaScript 吗?具体用处?
TypeScript
后简称(ts
)不能直接被javascript
后简称(js
) 解析器直接执行,ts
需要编译成js
方可执行后续操作。
js
是一门动态类型的语言,动态类型的自由特性容易导致错误,降低开发效率和时间工作成本。- 相较于
jS
而言,tS
拥有了静态类型,更加严格的语法,更强大的功能;TS
可以在代码执行前就完成代码的检查,减小了运行时异常的出现的几率; tS
代码可以编译为任意版本的jS
代码,可有效解决不同jS
运行环境的兼容问题;- 同样的功能,
tS
的代码量要大于jS
,但由于tS
的代码结构更加清晰,变量类型更加明确,在后期代码的维护中tS
却远远胜于jS
。 - 从技术上层面来说,
ts
就是具有静态类型的js
,ts
支持ES
的新特性,对数据类型进行判断等操作,有丰富的配置选项。
TypeScript的开发环境搭建
-
下载并安装
nodejs
(略)在终端使用
node -v
命令查找nodejs
版本号。例如:
- 安装好
nodejs
就可以使用ts
编译器
npm
<node
包管理器 >
-
安装
ts
,使用命令npm i -g typescript
命令,i
表示install
,g
表示global
,使用npm
全局安装ts
。 -
我使用的
IDE
是vscode
,您可以使用webstorm
等其他编辑器,在终端使用tsc
命令。
这样表示安装成功啦!同时可以使用常用命令(COMMON COMMANDS
),比如tsc -v
查看ts
的版本号。
创建第一个
ts
文件
- 命名为
01-hello.ts
- 内容为
console.log('Hello Ts');
- 上述谈到,
ts
需要编译为js
:在当前文件所在目录下开启终端(如vscode
开启终端快捷键 Ctrl + `)并使用命令tsc .\01-hello.ts
,对ts
文件进行编译。 - 然后在当前文件会生成
01-hello.js
(就目前两文件内容一致)
typeScript 与 javaScript 不同点
- 扩展了
types
。 - 类型。我们知道编程语言分为两类分别为静态类型或动态类型,使用静态类型的语言中,变量的类型在编译时必须是已知的。
- 比如声明一个变量,编译器应该知道(或可推断) 该变量是数值、字符串或布尔值;而在动态类型的语言中,只有在运行程序时才知道变量的类型。
ts
可以支持静态类型,而js
不支持。
基本类型
// 声明一个变量 同时指定它的类型为 number
let a;
// a 的类型设置为 number 以后再使用 a 的值类型 只能是 number
a = 10;
//a = 'hello';//报错
我们知道在 js
代码是没有问题,但同时伴随着许多安全隐患,比如代码中 a
第一次赋值为 number
类型 ,在第二次赋值变为 String
类型。
但需求是 a
一直是 Number
类型 ,而不是途中修改为其他类型,这很容易出现报错和错误难以发现的情况。再比如 'undefined' is not a function
。
类型声明
-
ts
向js
添加了静态类型 -
类型声明是
TS
非常重要的一个特征。 -
通过类型声明可以指定
TS
中变量(参数、形参)
的类型。 -
指定类型后,当为变量赋值时,
TS
编译器会自动检查值是否符合类型声明,符合则赋值,否则报错。简而言之,类型声明给变量设置了类型,使得变量只能存储某种类型的值。 -
指定类型后,当为变量赋值时,
TS
编译器会自动检查值是否符合类型声明,符合则赋值,否则报错。简而言之,类型声明给变量设置了类型,使得变量只能存储某种类型的值。
- 语法:
let 变量: 类型;
let 变量: 类型 = 值;
function fn(参数: 类型, 参数: 类型): 类型{
...
}
//声明完变量直接赋值
let c: boolean = true;
//let d: boolean = 123;//报错
let d = false;
//d = 123;//报错
//没有声明类型 依然报错
自动类型判断
-
TS
拥有自动的类型判断机制。 -
当对变量的声明和赋值是同时进行的,
TS
编译器会自动判断变量的类型,如果你的变量的声明和赋值时同时进行的,可以省略掉类型声明 -
代码块中没有给
d
声明类型,但还是报错了。
函数类型声明
Js
中的函数是不考虑参数的类型和个数,十分便利,但是同样伴随着安全隐患。- 我们尽量在编写代码时发现错误,而不是真正运行时才发现。
//js
function add(a, b) {
return a + b;
}
add(1, 2);//3
add(1, '2');//12
//---------------------水平分割线-------------------------
//ts
//number 数字数值类型
function sum(a: number, b: number) {
return a + b;
}
sum(1, 2);//3
//sum(1, '2');//报错
//sum(1, 2, 3);//报错
sum(1,'2')
报错原因是类型 “string”
的参数不能赋给类型“number”
的参数,
sum(1, 2, 3)
报错原因是应该只有 2 个参数,但现在获得 3 个参数。
function add1(a: number, b: number): number {
return a + b;
//return a + 'b';//报错
}
let res = sum(1, 2);//3
//函数返回值是 number
//let res: number
类型(
types
):
类型 | 例子 | 描述 |
---|---|---|
number | 1, -33, 2.5 | 任意数字 |
string | 'hi', "hi" | 任意字符串 |
boolean | true、false | 布尔值true 或false |
字面量 | 其本身 | 限制变量的值就是该字面量的值 |
any | * | 任意类型 |
unknown | * | 类型安全的any |
void | 空值(undefined ) | 没有值(或undefined ) |
never | 没有值 | 不能是任何值 |
object | {name:'zs'} | 任意的JS 对象 |
array | [1,2,3] | 任意JS 数组 |
tuple | [4,5] | 元素,TS 新增类型,固定长度数组 |
enum | enum{A, B} | 枚举,TS 中新增类型 |
类型很多,但不难理解,我们已经学了number
,我们逐个掌握!
//string
let a: string;
a = '10';// "" 或 '' 模板字符串 `${a}` 都可以
//let a: '10';
//也可以直接使用字面量进行类型声明
let b: 10;
b = 10;
//a = 11;//报错
//有点像 const 很少用 了解一下
|
联合类型,可以使用**|
**来连接多个类型
let b: 'male' | "female";
b = 'male';
b = 'female';
// b = 'undefined';//报错
// 类型“"undefined"”不可分配给类型“"male" | "female"”
let c: boolean | string;
c = true;
c = 'true';
any
表示任意类型
- 一个变量设置类型为
any
,相当于对该变量关闭了TS
类型校验,不建议使用。 - 注意:
let e
,声明了变量e
,其隐式具有any
类型。
let d: any;
//let e;//变量 "d1" 隐式具有 "any" 类型,但可以从用法中推断出更好的类型
d = 10;
d = '10';
d = true;
unknown
表示未知类型
- 相当于类型安全的
any
let e: unknown;
e = 10;
e = '10';
e = true;
//看上去跟 any 相似
any
与unknown
区别
unknown
类型变量不能直接赋值给其他变量。
let d: any;
d = '10';
let s: string;
s = d;
let e:unknown;
e = 10;
e = true;
e = 'true';
//s = e;//报错
d
的类型为any
,可以赋值给任何变量,不会报错,但是有很大的问题。s = e
报错,原因是不能将类型“unknown”
分配给类型“string”
,也就是不能将未知赋值给已知。- 如果不想报错,需要对
e
进行类型判断
if (typeof e === 'string') {
s = e;
}//有些麻烦,但是避免出现问题
//所以类型断言它的作用来了
类型断言
- 简单来说,就是告诉解析器变量的实际类型。
- 有些情况下,变量的类型对于我们来说是很明确,但是
TS
编译器却并不清楚,此时就可以通过类型断言来告诉编译器变量的类型,断言有两种形式。语法:变量 as 类型 或者 <类型>变量
。
let s: string;
let e: unknown;
s = e as string;
s = <string>e;//类似 java 中的泛型
函数
// js 普通函数声明
function fn() {
}
//没有返回值
function fn(): void
// 函数返回值为空值(没有值)
/*
function fn(num) {
if (num > 0) {
return true;
} else {
return 123;
}
}
*/
- 第10行-第16行注释的函数,报错原因是参数
"num"
隐式具有"any"
类型,但可以从用法中推断出更好的类型,所以我们在要尽可能的避免隐式any
的出现,也就是说需要确定变量的类型。
function fn(num: boolean | number) {
if (num > 0) {
return true;
} else {
return 123;
}
}
never 表示永远不会返回结果
- 返回“从不”的函数,不能具有可访问的终结点。
never
是没有值 ,不能是任何值
function fn(): never {
//报错
}
//如果要使用never的话需要 抛出异常
function fn(): never {
throw new Error('报错');
}
object
表示任意的对象
{}
用来指定对象中可以包含哪些属性;- 语法 :{属性名:属性值,…};
- 在属性名后边加上
?
, 表示属性为可选;
let a: object;
a = {};
a = function(){ };
a = [];
//“万物皆对象” java的朋友都出来吧!
let b: { name: string };
//注意区分 let b = { name: string };
//一个声明 一个赋值
//b = {};//报错
b = { name: 'zhangsan' };
//b = { name: 'zhangsan', age: 20 };//报错
b = {}
报错原因是类型"{}"
中缺少属性"name"
,但类型"{ name: string; }"
中需要该属性。b = { name: 'zhangsan', age: 20 }
报错原因是不能将类型“{ name: string; age: number; }”
分配给类型“{ name: string; }”
,也就是说“age”属性不在类型“{ name: string; }”
中,ts
中,对象可以只指定已知属性,不能指定未知属性。
let c: { name: string, age?: number };
c = { name: 'zhangsan' };
c = { name: 'zhangsan', age: 20 };
如果想要多个不定参数呢?
let d: { name: string, [propName: string]: any };
// d 要求有 name 属性 string 类型
// 可有其他属性 可有可无
propName
就是变量名,其表示任意字符串的属性名[propName: string]: any
表示任意类型的属性
d = { name: 'yyc' };
d = { name: 'yyc', age: 18, gender: 'male' };
> 设置函数结构的类型声明
>
> 语法 (形参:类型,形参:类型...) => 返回值
// e 要求是一个函数 有固定的几个参数 和 参数类型
let e: (a: number, b: number) => number;
e = function (n1: number, n2: number): number {
return n1 + n2;
}
// e = function (n1: number, n2: number,n3): number {
// return n1 + n2;
// }
// 报错
> 设置数组结构的类型声明
>
> 语法:`类型 [ ]` 或 ` Array<类型>`
let f: string[];
// 声明 f 字符串数组
f = ['1', '2', 'a'];
// f = ['1', '2', 'a', 1];//报错 不能将类型“number”分配给类型“string”。
// g 数值数组
let g: number[];
//有点像泛型
let h: Array<number>;
h = [1, 2, 3];
//h = [1, 2, 3,'1'];
//let h: Array<any>;//尽量少用
ts
增加js
没有的类型
tuple
:元组,是固定长度的数组
语法:[类型,类型,...]
let i: [string, string];
i = ['1', '2'];
// i = ['1', '2', '3'];//源具有 3 个元素,但目标仅允许 2 个
// i = ['1'];//源具有 1 个元素,但目标需要 2 个
// i = ['1', 2];//不能将类型“number”分配给类型“string”
enum
枚举
- 可以理解枚举就是一个字典,使用起来方便
let j: { name: string, gender: 0 | 1 };
j = {
name: 'zhangsan',
gender: 1,
}
console.log(j.gender === 1);//true
//gender 0 和 1 在这里没有意义 是男是女不清楚
//使用枚举
enum Gender {
Male = 0,
Female = 1,
}
let k: { name: string, gender: Gender };
k = {
name: 'yyc',
gender: Gender.Male,//很清楚知道是男
}
console.log(k.gender === Gender.Male);//true
&
表示 与,且,同时关系
//let l: string | number;
//let l: string & number;//没有意义
let l: { name: string } & { age: number };
//l = { name: 'yyc' };//报错
//类型 "{ name: string; }" 中缺少属性 "age",但类型 "{ age: number; }" 中需要该属性
l = { name: 'yyc', age: 20 };
type
作用:给类型起一个别名,支持基本类型、联合类型、元组等类型
//类型的别名 方便
//let m: 1 | 2 | 3 | 4;
//let n: 1 | 2 | 3 | 4;
//麻烦
type myType = string;
let m: myType;
type Type = 1 | 2 | 3 | 4;
let n: Type;
let z: Type;
编译选项
- 我们知道
ts
不能直接运行,需要使用命令tsc xxx.ts
编译成xxx.js
,但每次写好ts
文件都要重新手动调用上述命令,很麻烦,不方便。
自动编译文件
- 编译文件时,使用
-w
(watch)指令后,TS
编译器会自动监视文件的变化,并在文件发生变化时对文件进行重新编译。 - 使用命令
tsc xxx.ts -w
- 现在,每次修改完
ts
文件就能够自动编译文件,但是只能监视一个ts
文件,需求是想要编译多个文件呢?笨方法:一个文件开一个终端窗口, 100个文件开100个终端窗口,不适合日常开发。 - 将所有文件进行编译,需要配置文件
tsconfig.json
概述
- 如果一个目录下存在一个
tsconfig.json
文件,那么它意味着这个目录是TypeScript项目的根目录。 tsconfig.json
文件中指定了用来编译这个项目的根文件和编译选项。
配置文件
tsconfig.json
- 在当前文件的根目录下创建**
tsconfig.json
并输入{ }** - 此时如果在终端窗口直接使用
tsc
指令,则可以自动将当前项目下的所有ts
文件编译为js
文件。 tsconfig.json
是一个JSON
文件,可以写注释,是ts
编译器的配置文件, 只需tsc
命令即可完成对整个项目的编译。
配置选项
include
include
用来指定哪些ts
文件需要被编译- 路径:
*
表示任意文件,**
表示任意目录
{
"include":[
"src/**/*"
//编译src目录下的的任何ts文件
]
}
exclude
- 与
include
正好相反,用于指定不需要被编译的文件目录,定义需要排除在外的目录。 - 默认值:
["node_modules", "bower_components", "jspm_packages"]
- 有的文件不需要编译 ,文件路径写
exclude
内部
{
"exclude":[
"./src/hello/**/*"
]
}
- 上述示例中,
src
下hello
目录下的文件都不会被编译。
extends
- 定义被继承的配置文件
- 比如还有一个
xxx.json
想放入tsconfig.json
就可以用extends
配置选项,相当于引入外部文件 - 下述示例中,当前配置文件中会自动包含
config
目录下base.json
中的所有配置信息。
{
"extends": "./configs/base"
}
files
- 指定被编译文件的列表,只有需要编译的文件时才会使用到
- 下述示例中,列表中的文件都会被
TS
编译器所编译
{
//一般情况下 比较小的项目才会使用 一般不会用
"core.ts",
"sys.ts",
"types.ts",
"scanner.ts",
"parser.ts",
"utilities.ts",
"binder.ts",
"checker.ts",
"tsc.ts",
}
compilerOptions
-
编译选项是配置文件中非常重要也比较复杂的配置选项
-
在
compilerOptions
中包含多个子选项,用来完成对编译的配置
-
子选项
target
- 设置
ts
代码编译的目标版本 - 可选值:
ES3(默认)、ES5、ES6/ES2015、ES7/ES2016、ES2017、ES2018、ES2019、ES2020、ESNext
{ "compilerOptions":{ "target":"es2015" } }
图示:
m1.ts
文件 - 设置
target
为默认值(ES3
)
target
为ES2015
module
- 设置编译后代码使用的模块化系统
- 可选值:
CommonJS、UMD、AMD、System、ES2020、ESNext、None
{
"compilerOptions":{
"module": "CommonJS",
}
}
module
设置为System
lib
- 指定代码运行时所包含的库(宿主环境)
- 可选值:
ES5、ES6/ES2015、ES7/ES2016、ES2017、ES2018、ES2019、ES2020、ESNext、DOM、WebWorker、ScriptHost
{
"compilerOptions":{
"lib": ["dom"],
}
}
outDir
- 指定编译后文件所在目录
- 默认情况下,编译后的
js
文件会和ts
文件位于相同的目录,设置outDir
后可以改变编译后文件的位置 - 下述示例,设置后编译后的
js
文件将会生成到dist
目录
{
"compilerOptions":{
"outDir": "./dist",
}
}
outFile
- 将所有的文件编译为一个
js
文件 - 默认会将所有的编写在全局作用域中的代码合并为一个
js
文件,如果module
制定了None、System 或 AMD
则会将模块一起合并到文件之中 - outfile 仅支持
"amd"
和"system"
模块,也就是module
需要设置,下述示例,编译后的文件合并到dist 目录下 app.js
。
{
"compilerOptions":{
"outFile": "./dist/app.js",
}
}
rootDir
- 指定代码的根目录,默认情况下编译后文件的目录结构会以最长的公共目录为根目录,通过
rootDir
可以手动指定根目录
allowJs
- 表示是否对
js
文件进行编译,默认值为false
。
checkJs
- 表示是否检查
js
代码是否符合语法规范,默认值为false
。
// m2.js
let hh = 10;
hh = "hello"; //报错
// tsconfig.json 设置了 checkJs 为 true
// 不能将类型“string”分配给类型“number”
removeComments
- 表示是否移除注释,默认值为
false
。 - 图示
app.ts
中书写的注释
removeComments
为默认值app.js
- 设置
removeComments
为true
app.js
noEmit
- 不对代码进行编译,默认值为
false
。 - 不生成编译后的文件,比如用于查看编译是否通过,检查有无语法错误等
sourceMap
- 是否生成
sourceMap
,默认值为false
。
严格检查 (“use strict”)
strict
- 启用所有的严格检查,默认值为
true
,设置后相当于开启了所有的严格检查(如下)
alwaysStrict
- 总是以严格模式对代码进行编译
- 用来设置编译后的文件是否使用严格模式,默认值为
false
。
noEmitOnError
- 有错误不生成编译后的文件,默认值为
false
。
noImplicitAny
- 不允许隐式的
any
类型
function fn(a, b) {
return a + b;
}
//报错 有隐式 any
noImplicitThis
- 不允许有不明确类型的
this
function fn2() {
console.log(this);//this 不明确
//"this" 隐式具有类型 "any",因为它没有类型注释
}
//报错
//调用方式不明确 比如 严格模式 非严格模式 方法 函数调用等
//可以手动指定 this:window any...
function fn2(this:window) {
console.log(this);
}
strictNullChecks
- 严格的检查空值
【后面的了解为主】
strictBindCallApply
- 严格检查
bind、call和apply
的参数列表
strictFunctionTypes
- 严格检查函数的类型
strictPropertyInitialization
- 严格检查属性是否初始化
额外检查
noFallthroughCasesInSwitch
- 检查
switch
语句包含正确的break
noImplicitReturns
- 检查函数没有隐式的返回值
noUnusedLocals
- 检查未使用的局部变量
noUnusedParameters
- 检查未使用的参数
allowUnreachableCode
- 检查不可达代码
- 可选值:
true
,忽略不可达代码,false
,不可达代码将引起错误
tsconfig.json
源码文件 供大家学习参考
{
/* include 用来指定哪些 ts 文件需要被编译
路径: * 任意文件 ** 任意目录
*/
"include": [
"./src/**/*"
// 在配置文件“e:/Secret/javascript第二轮/ts/code2/tsconfig.json”中找不到任何输入。指定的 "include" 路径为“[
// "./src/**/*"
// ]”,"exclude" 路径为“[]”
],
/*
有些文件不需要编译 文件路径写这里
不需要被编译的文件目录
是有默认值 ["node_modules","bower_components","jspm_package"]
*/
"exclude": [
"./src/exclude/**/*"
],
/* "extends": []
定义被继承的配置文件
比如还有一个 xxx.json 想放入 tsconfig.json 就可以用 extends 相当于引入外部文件
"files":[]
指定被编译的文件的列表 只有需要编译的文件时才会使用到
一般情况下 比较小的项目才会使用 一般不会用
*/
/*
编译器选项
学习其子选项
*/
"compilerOptions": {
//target 用来指定 ts 被编译为 ES 版本
// "target": "ES3"
"target": "es2015",
// es3 es5 es6 es2015 es2016-2020 esnext
// ES3 app.ts --> app.js let a = 10 ; ==> var a = 10;
//js 本来没有模块化... es2015 commonJS
"module": "CommonJS",
// "lib": [
// ""
// ],
/*
lib 用来指定项目要使用的库 一般不需要动
"lib": ["dom"],
*/
"outDir": "./dist",
/*
outDir 指定编译后文件所在目录
*/
// outFile 将代码合并到一个文件
//"outFile": "./dist/app.js",
//outfile 仅支持 "amd" 和 "system" 模块
//编译后的文件合并到 app.js
//设置 outFile 后 所有全局作用域中的代码会合并到同一个文件
"allowJs": true,
// 是否对 js 文件进行编译 默认 false
"checkJs": true,
// 是否检查 js 代码 是否 符合语法规范 默认 false
// m2.js
//let hh = 10;
//hh = "hello"; 报错
//tsconfig.json 设置了 checkJs 为 true
//不能将类型“string”分配给类型“number”
//"removeComments": true,
//是否移除注释
"noEmit": false,
//不生成编译后的文件 比如说试错 看看编译是否通过 有无语法错误 用的比较少
"noEmitOnError": true,
//有错误不生成编译后的文件
//严格模式 use strict js 文件下加
//用来设置编译后的文件是否使用严格模式 默认为false
"alwaysStrict": true,
// 不允许隐式的any类型
"noImplicitAny": true,
//function fn(a, b) {
// return a + b;
// }报错 这里有隐式any
"noImplicitThis": true,
//不允许不明确类型的this
// function fn2() {
// console.log(this);//this 不明确
// //"this" 隐式具有类型 "any",因为它没有类型注释
// }
//调用方式不明确 比如 严格模式 非严格模式 方法 函数调用等
// 可以手动指定 this:window any...
"strictNullChecks": true,
//严格的检查空值
"strict": false,
//所有严格检查的总开关 如果为true 所有严格检查 都为 true
//开发一般设为true 不需要的单独设置为 false 让代码严谨 出错率低
},
}
第一期
TypeScript
学习内容就这么多啦,如果内容不错的话,望您能关注🤞点赞👍收藏❤️一键三连!