TypeScript 入门教程
TypeScript 是 JavaScript 的超集,为 JavaScript 添加了静态类型定义。本教程将帮助您从零开始学习 TypeScript。
什么是 TypeScript?
TypeScript 是由 Microsoft 开发的开源编程语言,它在 JavaScript 的基础上添加了静态类型定义。TypeScript 代码会被编译成纯 JavaScript 代码,可以在任何支持 JavaScript 的环境中运行。
主要优势
- 🔍 静态类型检查 - 在编译时发现错误
- 🛠️ 更好的 IDE 支持 - 智能提示、重构、导航
- 📚 更好的代码文档 - 类型即文档
- 🔧 更容易重构 - 类型安全的重构
- 🚀 渐进式采用 - 可以逐步迁移现有 JavaScript 项目
环境搭建
安装 TypeScript
bash
# 全局安装
npm install -g typescript
# 项目内安装
npm install -D typescript
# 检查版本
tsc --version
初始化项目
bash
# 创建 tsconfig.json
tsc --init
# 或者手动创建
mkdir my-ts-project
cd my-ts-project
npm init -y
npm install -D typescript @types/node
基本配置
json
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
基础类型
基本类型
typescript
// 布尔值
let isDone: boolean = false
// 数字
let decimal: number = 6
let hex: number = 0xf00d
let binary: number = 0b1010
let octal: number = 0o744
// 字符串
let color: string = "blue"
let fullName: string = `Bob Bobbington`
let age: number = 37
let sentence: string = `Hello, my name is ${fullName}.`
// 数组
let list: number[] = [1, 2, 3]
let list2: Array<number> = [1, 2, 3]
// 元组
let x: [string, number]
x = ["hello", 10] // OK
// 枚举
enum Color {
Red,
Green,
Blue,
}
let c: Color = Color.Green
// Any
let notSure: any = 4
notSure = "maybe a string instead"
notSure = false
// Void
function warnUser(): void {
console.log("This is my warning message")
}
// Null 和 Undefined
let u: undefined = undefined
let n: null = null
联合类型
typescript
// 联合类型
let value: string | number
value = "hello" // OK
value = 42 // OK
// 类型守卫
function padLeft(value: string, padding: string | number) {
if (typeof padding === "number") {
return Array(padding + 1).join(" ") + value
}
if (typeof padding === "string") {
return padding + value
}
throw new Error(`Expected string or number, got '${padding}'.`)
}
接口和类型
接口定义
typescript
// 基本接口
interface User {
name: string
age: number
email?: string // 可选属性
readonly id: number // 只读属性
}
const user: User = {
id: 1,
name: "张三",
age: 25,
email: "zhangsan@example.com"
}
// 函数接口
interface SearchFunc {
(source: string, subString: string): boolean
}
let mySearch: SearchFunc = function (source: string, subString: string): boolean {
let result = source.search(subString)
return result > -1
}
类型别名
typescript
// 基本类型别名
type Name = string
type NameResolver = () => string
type NameOrResolver = Name | NameResolver
function getName(n: NameOrResolver): Name {
if (typeof n === "string") {
return n
} else {
return n()
}
}
// 泛型类型别名
type Container<T> = { value: T }
函数
函数类型
typescript
// 函数声明
function add(x: number, y: number): number {
return x + y
}
// 函数表达式
let myAdd = function (x: number, y: number): number {
return x + y
}
// 箭头函数
let myAdd2 = (x: number, y: number): number => x + y
// 可选参数
function buildName(firstName: string, lastName?: string) {
if (lastName) return firstName + " " + lastName
else return firstName
}
// 默认参数
function buildName2(firstName: string, lastName = "Smith") {
return firstName + " " + lastName
}
// 剩余参数
function buildName3(firstName: string, ...restOfName: string[]) {
return firstName + " " + restOfName.join(" ")
}
类
基本类
typescript
class Animal {
private name: string
protected age: number
public species: string
constructor(name: string, age: number, species: string) {
this.name = name
this.age = age
this.species = species
}
public move(distanceInMeters: number = 0) {
console.log(`${this.name} moved ${distanceInMeters}m.`)
}
protected getAge(): number {
return this.age
}
}
class Dog extends Animal {
constructor(name: string, age: number) {
super(name, age, "Dog")
}
public bark() {
console.log("Woof! Woof!")
}
public getAgeInDogYears(): number {
return this.getAge() * 7
}
}
泛型
基本泛型
typescript
// 泛型函数
function identity<T>(arg: T): T {
return arg
}
let output = identity<string>("myString")
let output2 = identity("myString") // 类型推断
// 泛型接口
interface GenericIdentityFn<T> {
(arg: T): T
}
// 泛型类
class GenericNumber<T> {
zeroValue: T
add: (x: T, y: T) => T
constructor(zeroValue: T, addFn: (x: T, y: T) => T) {
this.zeroValue = zeroValue
this.add = addFn
}
}
let myGenericNumber = new GenericNumber<number>(0, (x, y) => x + y)
泛型约束
typescript
interface Lengthwise {
length: number
}
function loggingIdentity<T extends Lengthwise>(arg: T): T {
console.log(arg.length)
return arg
}
loggingIdentity({ length: 10, value: 3 }) // OK
高级类型
映射类型
typescript
// Partial - 将所有属性变为可选
type Partial<T> = {
[P in keyof T]?: T[P]
}
interface User {
name: string
age: number
email: string
}
type PartialUser = Partial<User>
// Pick - 选择部分属性
type Pick<T, K extends keyof T> = {
[P in K]: T[P]
}
type UserNameAndAge = Pick<User, 'name' | 'age'>
// Omit - 排除部分属性
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>
type UserWithoutEmail = Omit<User, 'email'>
条件类型
typescript
// 基本条件类型
type TypeName<T> = T extends string
? "string"
: T extends number
? "number"
: T extends boolean
? "boolean"
: "object"
type T0 = TypeName<string> // "string"
type T1 = TypeName<true> // "boolean"
实用工具类型
typescript
interface User {
id: number
name: string
email: string
age: number
}
// Partial<T> - 所有属性可选
type PartialUser = Partial<User>
// Required<T> - 所有属性必需
type RequiredUser = Required<PartialUser>
// Readonly<T> - 所有属性只读
type ReadonlyUser = Readonly<User>
// Record<K, T> - 创建对象类型
type UserRoles = Record<'admin' | 'user' | 'guest', User>
// ReturnType<T> - 获取函数返回类型
type T3 = ReturnType<() => string> // string
// Parameters<T> - 获取函数参数类型
type T4 = Parameters<(a: string, b: number) => void> // [string, number]
最佳实践
严格模式配置
json
{
"compilerOptions": {
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"noImplicitReturns": true
}
}
类型断言的正确使用
typescript
// 避免使用 any
let someValue: unknown = "this is a string"
// 使用类型断言
let strLength: number = (someValue as string).length
// 或者使用类型守卫
function isString(value: unknown): value is string {
return typeof value === 'string'
}
if (isString(someValue)) {
let strLength: number = someValue.length
}
优先使用接口
typescript
// 推荐:使用接口
interface User {
name: string
age: number
}
// 接口可以扩展
interface AdminUser extends User {
permissions: string[]
}
// 类型别名适用于联合类型
type Status = 'loading' | 'success' | 'error'
type ID = string | number
常见问题
什么时候使用 interface,什么时候使用 type?
- 定义对象结构时优先使用
interface
- 定义联合类型、原始类型别名时使用
type
- 需要使用映射类型、条件类型时使用
type
如何处理第三方库的类型?
bash
# 安装类型定义
npm install --save-dev @types/lodash
typescript
// 或者自己声明
declare module 'some-library' {
export function someFunction(): void
}
如何在现有项目中引入 TypeScript?
- 安装 TypeScript 和相关依赖
- 创建
tsconfig.json
配置文件 - 将
.js
文件逐步重命名为.ts
- 添加类型注解
- 解决类型错误
总结
TypeScript 为 JavaScript 开发带来了类型安全和更好的开发体验。通过掌握基础类型、接口、泛型等核心概念,您可以编写更可靠、更易维护的代码。
建议从小项目开始实践,逐步熟悉 TypeScript 的各种特性,最终能够在大型项目中充分发挥 TypeScript 的优势。
继续学习: