本文已参与「新人创作礼」活动,一起开启掘金创作之路。
前言
本文主要内容:通过多个例子讲述如何使用TypeScript,以及总结一些TypeScript学习过程中的重要知识点
接下来的目标是加快脚步扩充自己的技能包。争取在这个月下旬重新写一遍自己的个人网站作为前端项目,而TypeScript就是学习的其中一环。
一个例子说明为何以及如何使用TS
这个例子是我看了好多教程文章都会提到的简单例子,首先可以看下HTML架构如下
<!DOCTYPE html>
<html lang="en">
<head>
<title>UnderStanding TypeScript</title>
</head>
<body>
<input type="number" id="num1" placeholder="Number 1" />
<input type="number" id="num2" placeholder="Number 2" />
<button>ADD</button>
<script src="./index.js"></script>
</body>
</html>
两个输入框和一个按钮,目标是在两个输入框中输入数字,然后点击按钮能在控制台显示相加结果
所以我们可以很快地写出来如下代码
const button = document.querySelector("button");
const input1 = document.getElementById("num1");
const input2 = document.getElementById("num2");
function add(num1, num2) {
return num1 + num2;
}
button.addEventListener("click", function() {
console.log(add(input1.value, input2.value));
});
可以看到对dom元素进行了操作,看下结果如下
不出意外的出意外了,显然我们没有类型加以限制,导致结果变成了两个字符串的拼接
所以接下来让我们看一下用ts会得到什么样的情况
同样的代码复制到 index.ts 中却是报了很多的错误,所以当我们进行如下修改
const button = document.querySelector("button");
const input1 = document.getElementById("num1")! as HTMLInputElement;
const input2 = document.getElementById("num2")! as HTMLInputElement;
function add(num1: number, num2: number) {
return num1 + num2;
}
button!.addEventListener("click", function() {
console.log(add(+input1.value, +input2.value));
});
文件便不再报错了。
然而TS是不能被浏览器执行的,它是作为一个编译器,能将ts文件编译成js文件,然后进一步运行编译得到的js文件来实现同样的功能
所以首先 npm install -g typescript 安装ts包
然后 tsc index.ts 对ts文件进行编译,获得 index.js 文件,如下
var button = document.querySelector("button");
var input1 = document.getElementById("num1");
var input2 = document.getElementById("num2");
function add(num1, num2) {
return num1 + num2;
}
button.addEventListener("click", function () {
console.log(add(+input1.value, +input2.value));
});
再次运行发现获得正确结果
可以看到后续编译生成的js文件和一开始写的js文件实际上就多了类型的转换,而这也就说明了ts主要的优势是在编写代码的过程中确保代码的安全性
TS 基础类型
TS的基础用法实际上就和上面的例子一样简单,它有着和js一样的三种基本类型,即 number string boolean
TS能定义变量的类型,也能对类型进行简单的逻辑判断,能减少语法正确但是逻辑错误出现的概率
比如下面的例子
const reviews = [
{
name: 'Sheia',
stars: 5,
loyaltyUser: true,
date: '01-04-2021'
},
{
name: 'Andrzej',
stars: 3,
loyaltyUser: false,
date: '28-03-2021'
},
{
name: 'Omar',
stars: 4,
loyaltyUser: true,
date: '27-03-2021'
},
]
function showReviewTotal (value : number, reviewer: string, isLoyalty : boolean) {
const iconDisplay = isLoyalty ? '⭐' : ''
reviewTotalDisplay!.innerHTML = 'review total ' + value.toString() + '| last reviewed by ' + reviewer + ' ' + iconDisplay
}
showReviewTotal(reviews.length, reviews[0].name, reviews[0].loyaltyUser)
使用TS接收了三种数据类型的参数,一旦其中发现错误,编译就会失败
TS 复杂类型
除了三种基础类型,还有一些更复杂的类型,即一些结构化的类型
Object
首先是对象类型,基础的定义如下
const you: object = {
userName: 'heheer',
isReturning: true,
}
可以看到定义了一个object类型的you变量,包含两个属性
可以将object等效替换为 {}
而这个 {} 中还能进一步做文章,如下
const you: {
userName: string;
isReturning: boolean;
} = {
userName: 'heheer',
isReturning: true,
}
可以看到我们能对属性的类型也做出限制
Array
第二个要介绍的是数组类型,它的基础定义略有不同。我们同样在you对象中添加属性,如下
const you: {
userName: string;
isReturning: boolean;
hobbies: string[];
} = {
userName: 'heheer',
isReturning: true,
age: 20,
hobbies: ['cooking', 'photography', 'badminton']
}
可以看到定义数组时不能使用array说明类型,而是要同时说明数组元素的类型,这样当我们加入一个新的元素20时,可以发现报错了
至于如何实现数组包含多个类型,如下
hobbies: (string | number)[];
这样就能在数组中添加字符串和数字两种元素
Tuple
第三个是元组类型,在使用的时候往往长得和数组很像,但是实际上有比较大的不同,可以看到基础用法如下
const you: {
...
contact: [number, string]
} = {
...
contact: [88888888, 'xxxxxx@outlook.com']
}
也就是元组的定义会逐个定义其中的元素,此后使用元组需要保证元素的类型与元素的数目都与定义一致,否则就会报错编译失败
Enum
第四个是枚举类型,这个类型可能有一点不好理解,看一个例子如下
const ADMIN = 'admin'
const READ_ONLY = 'read-only'
enum Permissions {
ADMIN,
READ_ONLY
}
可以看到我们定义了两个枚举成员,将它们包含在了Permissions这个枚举中,使用时如下
permissions: Permissions.ADMIN,
所以接下来我们看一下编译出来的js代码
var Permissions
(function (Permissions){
Permissions[Permissions['ADMIN']='admin']='ADMIN';
Permissions[Permissions['READ_ONLY']='read-only']='READ_ONLY';
})(Permissions || (Permissions={}));
可以看到在js代码中,Permissions被编译成了一个包含双向映射的对象,也就意味着能够通过引用枚举可以访问其中的属性且不会生成内联,有较高的安全性
Any
Any类型感觉是一个有一些矛盾的类型,TypeScript规范了JS中的类型,然而使用any能够在TS中随心所欲地定义变量,如下两个不同格式的数组能在any类型下不报错
const reviews : any = [
{
name: 'Sheia',
stars: 5,
loyaltyUser: true,
date: '01-04-2021'
},
{
name: 'Andrzej',
stars: 3,
loyaltyUser: false,
date: '28-03-2021',
test: 'test'
}
]
然而这种偷懒不是太好,我们可以使用这种方法来保持严谨
const reviews : (
{
name: string;
stars: number;
loyaltyUser: boolean;
date: string;
} |
{
name: string;
stars: number;
loyaltyUser: boolean;
date: string;
test: string;
}
)[] = [
{
name: 'Sheia',
stars: 5,
loyaltyUser: true,
date: '01-04-2021'
},
{
name: 'Andrzej',
stars: 3,
loyaltyUser: false,
date: '28-03-2021',
test: 'test'
}
]
也就是利用数组的定义方式,定义多种类型的数组元素
Union
Union类型的关键在于 |,这个管道符,它允许一个变量拥有多个类型,也就是和在数组中定义类似
test: number | string
所以此时我们可以向test中传入两种类型的数据
Literal
字面类型,是对三种基本类型的数据进行限制,如下
type Price = 45 | 30 | 25
price: Price;
price: 45
可以看到第一行我们定义了三个字面量作为Price类型,然后限制price为Price类型,所以此时price只能接受Price中的三个字面量
同样的,还可以定义字面量为string类型和boolean类型的字面类型
小结
本文对TypeScript中的各种类型做了一些总结,可以看到TS在规范JS的类型中还是做了很多努力的,限制了原有的三大基本类型,并引入了Tuple、Enum、Literal等类型对数据类型进行了进一步的规范。