【TypeScript】如何使用TS | TS的几种类型

261 阅读6分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

前言

本文主要内容:通过多个例子讲述如何使用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元素进行了操作,看下结果如下

image.png

不出意外的出意外了,显然我们没有类型加以限制,导致结果变成了两个字符串的拼接

所以接下来让我们看一下用ts会得到什么样的情况

image.png

同样的代码复制到 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));
});

再次运行发现获得正确结果

image.png

可以看到后续编译生成的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等类型对数据类型进行了进一步的规范。