TypeScript 基础:类型系统入门
JavaScript 是动态类型语言,变量类型在运行时才确定。这带来了灵活性,但也导致了很多运行时错误。TypeScript 给 JavaScript 加上了静态类型系统,让错误在编译时就能被发现。
这一期,我们学习 TypeScript 的基础类型系统。
为什么需要 TypeScript
JavaScript 的痛点
// 这段代码在 JavaScript 中完全合法
let name = "Alice"
name = 123 // 没有报错
name.toUpperCase() // 运行时报错:name.toUpperCase is not a function
TypeScript 的解决方案
let name: string = "Alice"
name = 123 // 编译时报错:Type 'number' is not assignable to type 'string'
TypeScript 的优势
| 优势 | 说明 |
|---|---|
| 类型安全 | 编译时发现错误 |
| 智能提示 | IDE 自动补全 |
| 代码文档 | 类型即文档 |
| 重构友好 | 改代码有信心 |
安装 TypeScript
全局安装
npm install -g typescript
项目安装
npm install typescript --save-dev
初始化配置
npx tsc --init
这会生成 tsconfig.json 文件。
基础类型
布尔值
let isDone: boolean = false
数字
let decimal: number = 6
let hex: number = 0xf00d
let binary: number = 0b1010
let octal: number = 0o744
字符串
let color: string = "blue"
color = 'red'
color = <code>green
数组
// 方式1:元素类型后面接 []
let list1: number[] = [1, 2, 3]
// 方式2:使用数组泛型
let list2: Array = [1, 2, 3]
元组
元组表示已知元素数量和类型的数组。
let tuple: [string, number]
tuple = ["hello", 10] // OK
tuple = [10, "hello"] // Error
访问元素:
console.log(tuple[0].substring(1)) // OK
console.log(tuple[1].substring(1)) // Error, number 没有 substring
枚举
enum Color {
Red,
Green,
Blue
}
let c: Color = Color.Green
console.log(c) // 1
自定义值:
enum Color {
Red = 1,
Green = 2,
Blue = 4
}
let c: Color = Color.Green
反向映射:
enum Color {
Red = 1,
Green,
Blue
}
let colorName: string = Color[2]
console.log(colorName) // 'Green'
any
任意类型,放弃类型检查。
let notSure: any = 4
notSure = "maybe a string"
notSure = false
注意:尽量少用 any,否则就失去了 TypeScript 的意义。
unknown
类型安全的 any。
let notSure: unknown = 4
// 必须类型检查后才能使用
if (typeof notSure === "number") {
console.log(notSure.toFixed(2))
}
void
没有任何类型,通常用于函数返回值。
function warnUser(): void {
console.log("This is my warning message")
}
null 和 undefined
let u: undefined = undefined
let n: null = null
默认情况下 null 和 undefined 是所有类型的子类型。
never
永不存在的值的类型。
// 抛出异常的函数
function error(message: string): never {
throw new Error(message)
}
// 无限循环
function infiniteLoop(): never {
while (true) {}
}
object
非原始类型。
declare function create(o: object | null): void
create({ prop: 0 }) // OK
create(null) // OK
create(42) // Error
create("string") // Error
类型断言
告诉 TypeScript "我知道这个类型"。
尖括号语法
let someValue: any = "this is a string"
let strLength: number = (someValue).length
as 语法(推荐)
let someValue: any = "this is a string"
let strLength: number = (someValue as string).length
类型推断
TypeScript 会自动推断类型。
let x = 3 // 推断为 number
let y = "hello" // 推断为 string
// 从右向左推断
let z = x + 1 // number
联合类型
表示可以是多种类型之一。
let id: string | number
id = "abc123" // OK
id = 123 // OK
id = false // Error
实际应用:
function formatValue(value: string | number) {
if (typeof value === "string") {
return value.toUpperCase()
} else {
return value.toFixed(2)
}
}
字面量类型
精确到具体的值。
let x: "hello"
x = "hello" // OK
x = "world" // Error
联合字面量:
type Direction = "up" | "down" | "left" | "right"
function move(dir: Direction) {
// ...
}
move("up") // OK
move("north") // Error
类型别名
给类型起个名字。
type Name = string
type NameResolver = () => string
type NameOrResolver = Name | NameResolver
function getName(n: NameOrResolver): Name {
if (typeof n === "string") {
return n
} else {
return n()
}
}
实践建议
1. 避免使用 any
// Bad
let data: any = fetchData()
// Good
interface User {
id: number
name: string
}
let data: User = fetchData()
2. 使用类型推断
// Bad
let x: number = 10
// Good(让 TS 推断)
let x = 10
3. 优先使用 interface
// Bad
type User = {
name: string
}
// Good(interface 可扩展)
interface User {
name: string
}
4. 使用严格模式
在 tsconfig.json 中启用:
{
"compilerOptions": {
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true
}
}
总结
TypeScript 的基础类型系统包括:
- 原始类型:boolean, number, string
- 复合类型:array, tuple, enum
- 特殊类型:any, unknown, void, never
- 类型操作:联合类型、类型断言、类型推断
掌握了这些,你已经可以用 TypeScript 写代码了。下一期,我们学习接口、泛型和高级类型。
学习资源:
Views: 0
