最近开始学习 TypeScript,发现很多项目已经默认使用 TS 开发了,例如 React、Vue、NestJS 等。
刚开始学习的时候,我一直有几个疑问:
- JavaScript 为什么不需要声明类型?
- 什么是动态语言?什么是静态语言?
- TypeScript 到底是不是一门新的语言?
- 为什么大家都说 TS 能提高代码质量?
这篇文章主要记录一下自己的学习过程,希望能帮助和我一样刚开始学习 TypeScript 的同学。
JavaScript 是一门弱类型动态语言
想理解 TypeScript,就要先理解 JavaScript。
JavaScript 有两个非常重要的特点:
- 动态语言(Dynamic)
- 弱类型语言(Weakly Typed)
什么是动态语言?
动态指的是:
变量的类型是在程序运行时确定的。
JavaScript 代码交给 V8 引擎执行时,V8 会根据变量当前保存的数据来判断它是什么类型,然后再决定如何操作。
例如:
ini
let num = 10
let str = "hello"
let flag = true
我们在声明变量的时候:
typescript
并没有告诉 JavaScript:
这是 number
这是 string
这是 boolean
但是程序依然可以正常运行。
因为:
V8 会在运行过程中自动判断变量类型。
这就是:
sql
动态类型(Dynamic Typing)
什么是弱类型?
弱类型指的是:
变量的类型可以随时改变。
例如:
ini
let value = 100
value = "Hello"
value = true
同一个变量:
既可以保存数字。
也可以保存字符串。
甚至可以保存布尔值。
JavaScript 都不会报错。
因此:
JavaScript 是弱类型语言。
JavaScript 为什么设计成这样?
JavaScript 最初的目标就是:
简单、灵活、容易上手。
因此:
开发者不用声明变量类型。
写代码速度非常快。
但是:
灵活的同时也意味着:
容易出现类型错误。
例如:
scss
function add(a, b) {
return a + b
}
add(1, 2) // 3
add("1", 2) // "12"
同一个函数:
不同类型会得到完全不同的结果。
大型项目中:
这种问题很难排查。
什么是强类型静态语言?
与 JavaScript 相反。
很多语言属于:
强类型静态语言。
例如:
- Java
- Go
- C#
- Rust
它们都有两个特点。
静态类型
静态指的是:
编译阶段就会检查变量类型。
例如:
Go:
csharp
var age int = 18
Java:
ini
int age = 18;
变量类型:
写代码的时候
就已经确定了。
如果类型错误:
编译器直接报错。
不会等到程序运行。
强类型
强类型指的是:
变量类型不能随意改变。
例如:
ini
var age int = 18
age = "Hello"
编译器会直接报错。
因为:
c
int
不能变成
string
因此:
强类型语言
能够提前发现很多错误。
JavaScript 与强类型语言对比
| JavaScript | Java / Go |
|---|---|
| 动态类型 | 静态类型 |
| 弱类型 | 强类型 |
| 运行时检查 | 编译时检查 |
| 不需要声明类型 | 必须声明类型 |
所以:
JavaScript 开发速度快。
而:
Java、Go 更安全。
TypeScript 是什么?
TypeScript 官方定义:
TypeScript 是 JavaScript 的超集(Superset)。
什么意思?
就是说:
所有 JavaScript 都是合法的 TypeScript。
例如:
JavaScript:
ini
let name = "Rose"
TypeScript 同样可以运行。
但是:
TS 又新增了:
类型系统。
例如:
ini
let name: string = "Rose"
let age: number = 18
这样:
变量类型更加明确。
TypeScript 是一门新的语言吗?
不是。
TypeScript 本质还是:
JavaScript。
只是:
增加了:
- 类型检查
- 编译时错误检查
- 更完善的开发体验
浏览器:
不能直接运行 TS。
因为:
浏览器只认识:
JavaScript。
所以:
TypeScript 需要经过:
TypeScript Compiler(tsc)
编译成:
JavaScript。
然后浏览器再执行。
整个流程:
TypeScript
↓
tsc 编译器
↓
JavaScript
↓
浏览器
TypeScript 为什么越来越流行?
最大的原因就是:
大型项目需要类型。
例如:
一个团队:
几十个人一起开发。
如果:
javascript
function getUser(data){}
没人知道:
kotlin
data
到底是什么?
但是:
TypeScript:
javascript
function getUser(data: User){}
一眼就知道:
sql
参数必须是 User 类型。
阅读代码更加轻松。
维护成本也更低。
TypeScript 常见类型
学习 TS,首先要掌握类型系统。
基本类型
typescript
let age: number = 18
let name: string = "Rose"
let isLogin: boolean = true
let a: null = null
let b: undefined = undefined
除此之外:
还有:
typescript
symbol
bigint
any
swift
let value: any
any 表示:
关闭类型检查。
变量可以保存任何类型。
例如:
ini
value = 10
value = "hello"
value = true
一般:
arduino
不推荐大量使用 any。
否则:
TypeScript 就失去了意义。
object 与 Object
很多初学者容易混淆。
object
表示:
狭义对象。
例如:
scss
{}
[]
function(){}
Object
表示:
广义对象。
几乎所有引用类型都属于:
css
Object
数组与元组
数组:
ini
let arr:number[]=[1,2,3]
元组:
ini
let user:[string,number]
user=["Rose",18]
元组:
长度固定。
每个位置类型固定。
Type
Type 可以:
定义一个类型别名。
例如:
typescript
type User={
name:string
age:number
}
以后:
sql
let user:User
即可复用。
Interface
Interface:
主要用于:
定义对象结构。
例如:
typescript
interface User{
name:string
age:number
}
它与 Type 很相似。
但:
Interface 更适合描述对象。
泛型(Generic)
泛型可以理解成:
类型参数。
例如:
r
function getData<T>(value:T):T{
return value
}
这样:
函数可以适配:
- number
- string
- object
不用重复编写多个版本。
类型断言
有时候:
开发者比 TypeScript 更清楚变量类型。
可以使用:
csharp
value as string
告诉编译器:
c
我确定它是 string。
这就是:
python
类型断言(Type Assertion)
keyof
keyof 可以获取:
对象所有键组成的联合类型。
例如:
typescript
interface User{
name:string
age:number
}
得到:
sql
keyof User
// "name" | "age"
它在封装工具函数时非常常见。
装饰器(Decorator)
装饰器本质上就是:
给类、方法、属性
增加额外功能。
例如:
NestJS 中大量使用:
less
@Controller()
@Get()
@Post()
@Injectable()
这些都是:
Decorator。
我的理解
学习 TypeScript 后,我最大的感受就是:
JavaScript 更自由。
TypeScript 更规范。
对于小项目:
JavaScript 已经足够。
但是:
对于大型项目。
多人协作。
长期维护。
TypeScript 能提前发现很多问题。
因此:
现在越来越多的企业项目都会默认使用:
TypeScript + React
TypeScript + Vue
TypeScript + Node.js
作为开发技术栈。
总结
一句话记住今天的内容:
JavaScript 是一门弱类型动态语言,
变量类型在运行时确定,并且可以随意改变。
TypeScript 是 JavaScript 的超集,
它增加了类型系统和编译时检查,
帮助开发者在编码阶段发现错误,提高代码的可维护性和开发效率。