前言
本文会系统的介绍TS
的基本使用,属于入门级文章,当然需要一些JS的基本知识, 看完本文你就可以使用TS
了,当然TS
是一门使用很简单但是用好却有点难度的JS
超集,在各种复杂的使用场景中应该多思考TS
的更佳实践!
TS简介
TypeScript 是一种由微软开发的开源编程语言,它是 JavaScript 的一个超集,它只存在于编译时态,并不参与运行。它扩展了 JavaScript,为其添加了静态类型检查、支持最新的 ECMAScript 特性、面向对象编程的功能,以及更强大的工具支持。TypeScript 的主要目标是使大型应用程序的开发更加容易,提高代码的可维护性和可读性。
TypeScript 的特点包括:
- 静态类型检查: TypeScript 引入了静态类型系统,使开发者可以在编码阶段就能够发现并修复潜在的类型错误,提高了代码的可靠性和稳定性。
- ECMAScript 支持: TypeScript 支持最新的 ECMAScript 标准,并且不断更新以跟进 JavaScript 的最新发展,包括 ES6、ES7 等新特性,让开发者能够更加方便地使用 JavaScript 最新的语言功能。
- 面向对象编程: TypeScript 支持面向对象编程的特性,包括类、接口、继承、多态等,使得代码结构更加清晰、模块化,便于团队协作和代码复用。
- 工具支持: TypeScript 提供了强大的工具支持,包括丰富的编辑器集成(如 Visual Studio Code)、自动代码补全、重构工具、代码格式化工具等,使开发者能够更高效地编写和维护代码。
- 增强的错误提示: TypeScript 提供了更加友好和详细的错误提示信息,帮助开发者快速定位和修复问题。
- 渐进式采用: TypeScript 是一种渐进式的语言,意味着可以在已有的 JavaScript 项目中逐步引入 TypeScript,而无需对整个项目进行重写。
总的来说,TypeScript 是一种强大的编程语言,它融合了 JavaScript 的灵活性和动态特性,以及静态类型检查和面向对象编程的优点,为开发者提供了更好的开发体验和更高的代码质量。
TS的声明类型
在 TypeScript 中,可以使用类型注解来声明变量、函数参数和返回值等的类型。类型注解使用冒号(:)后跟类型名称的方式来指定类型。下面是一个简单的 TypeScript 文件,并对其中的变量和函数进行了类型声明:
typescript
// 声明一个字符串变量,并指定其类型为 string
let myName: string = "John";
// 声明一个数字变量,并指定其类型为 number
let myAge: number = 30;
// 声明一个布尔变量,并指定其类型为 boolean
let hasPets: boolean = true;
// 声明一个函数,指定参数和返回值的类型
function greet(name: string): string { return "Hello, " + name; }
// 调用函数,并传入参数,根据函数返回值类型推断出变量类型
let greetingMessage = greet(myName);
// 输出结果
console.log(greetingMessage); // 输出:Hello, John
TS实践
首先可以跟随笔者开始简单的使用TS,我们打算使用TS的情况下,开发一个简单的计数器,既然是学习TS, 那我们就不使用脚手架了, 项目由我们逐步搭建
TS项目开发
新建一个ts-count-demo
的空文件夹vscode
打开,新建一个 hmtl 文件,简单布局一下,一个显示数字的元素,两个按钮控制数值的加减,这个代码很基础,就不多赘述了
xml
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>count</title>
<style>
#app {
padding: 100px 0;
text-align: center;
}
button {
padding: 8px 12px;
border-radius: 3px;
border: none;
cursor: pointer;
box-shadow: 0 5px 0 0 #2461ab;
font-size: 16px;
background: #3f89e3;
color: #fff;
margin: 0 8px;
}
button:active {
box-shadow: 0 1px 0 0 #2461ab;
transform: translateY(3px);
}
</style>
</head>
<body>
<div id="app">
<p>当前数值为:<span id="count">0</span></p>
<button id="add">add</button>
<button id="minus">minus</button>
</div>
</body>
</html>
接着新建一个 index.ts
来开始实现JS部分, 首先我们写一个函数getDom
用来获取DOM元素,这个函数接受一个字符串作为参数,会返回该字符串的DOM元素
javascript
function getDom(tag: string): HTMLElement {
const dom = document.querySelector(tag)
if (!dom) {
new Error(`通过${tag}没有找到对应的dom元素,请检查代码是否写错了`)
}
return dom as HTMLElement
}
通过传入的tag来获取类型,同时声明该函数返回的类型为 HTMLElement(这是TS的一个内置类型), 接着函数内部通过document.querySelector(tag)
来获取元素并赋值给变量dom
, 此时dom
被TS
推断为HTMLElement | null
,这是因为传入的tag
通过querySelector
并不一定能获取到dom元素,我们判断如果没有dom就报错,接着通过as
来断言dom一定是HTMLElement
类型便于我们后续使用值时不用反复的去断言,在 TypeScript 中,as
关键字用于类型断言,它的作用是告诉编译器某个值的类型,以便在编译阶段进行类型检查或类型推断。
接着我们需要一个更改 count 的函数onChangeCount
,这个函数需要一个参数operationType
,因为我们有加减两个按钮来更改count,所以需要根据调用函数时传入的操作类型来处理count, 参数operationType
的类型为字符串当然是可以的,但是这样就无法保证在调用函数时传参随意导致函数不能被正确调用,所以这里我们需要声明一个类型约束传入的值
ini
let count = 0;
const countVal = getDom('#count')
type OperationType = 'add' | 'minus'
enum OperationTypeEnum {
ADD = 'add',
MINUS = 'minus',
}
function onChangeCount(operationType: OperationTypeEnum) {
if (operationType === 'add') {
count++
} else {
count--
}
countVal.innerText = String(count)
}
TS较为常用声明类型的方式有interface(接口) ,enum(枚举) ,type(类型) ,上面代码中我分别声明了 联合类型(Union Types) 和 enum(枚举) , 最后我使用了枚举来定义operationType
的类型,其实上述两种写法都是OK的。在修改了对应的count值之后,我们需要把countVal的文本内容修改为count, 这里就能体现出 TS 的约束了, 由于 count 定义时是0, TS推导出 count 的类型为 number, 此时如果直接countVal.innerText = count
那么TS会直接给我们报错不能将number类型分配给string类型
,所以我们需要把 count 通过String()
函数转换一下, 在实际的项目开发中,这种错误很可能就会疏忽, 需要到运行时才能被捕获,而是用了TS, 编译时就能帮你看到问题,避免了放入测试环境才发现问题
最后通过给 add 和 minus 按钮添加事件调用修改 count 函数即可完成我们的需求了
scss
const addBtn = getDom('#add')
const minusBtn = getDom('#minus')
addBtn.addEventListener('click', () => onChangeCount(OperationTypeEnum.ADD))
minusBtn.addEventListener('click', () => onChangeCount(OperationTypeEnum.MINUS))
此时代码已经写完了, 尝试本地运行一下文件,一般通用的手段就是nodejs
搭建一个本地环境, 或者使用serve liver
, 接着在index.html
中引入该 index.ts
, 不过通过这样做会报一个 MIME
类型的错误, 这个问题通常是由于服务器返回的 MIME 类型不正确所导致的。浏览器预期加载的是 JavaScript 模块脚本,但服务器却返回了错误的 MIME 类型(例如 video/mp2t
), 如果使用的是 Express ,那么可以使用中间件来指令类型,例如:
javascript
const express = require('express');
const app = express();
app.use(express.static('public', {
setHeaders: (res, path, stat) => {
if (path.endsWith('.ts')) {
res.setHeader('Content-Type', 'application/javascript');
}
},
}));
app.listen(3000, () => { console.log('Server is running on port 3000'); })
我就直接把 ts 文件编译出来之后引入编译文件吧, 全局安装TS
css
npm i -g typescript
在项目下使用
tsc index.ts
这样打包好了一个同名的index.js
文件了,可以去看看这里面的源码, 引入该文件后也可以本地服务去看看具体的效果
文末
在本次示例中,我们简单的使用了TS来实现了一个小功能,使用了TS的内置函数,类型声明,以及打包TS文件,体会到了TS给我们开发中带来了约束的重要性,这在多人协作开发中或者维护一个长久的项目中很有效,可以避免很多错误的发生, 如果对TS有深入学习的兴趣,可以关注本文专栏,后续会写更多的TS技巧。