TypeScript 入门教程 — JavaScript 的超集

前置要求:JavaScript基础
学习时长:约2-3天(每天3小时)
TypeScript版本:5.x
适用场景:大型项目、团队协作、企业级应用

一、TypeScript 是什么?

TypeScript 是 JavaScript 的超集,添加了类型系统,可以在编译时发现错误,提高代码质量和开发效率。

特点说明
类型安全编译时检查类型错误
智能提示IDE自动补全更准确
代码可读性类型即文档
兼容性完全兼容JavaScript
学习成本有JS基础1-2天可入门

二、安装与配置

# 安装TypeScript
npm install -g typescript

# 初始化配置
tsc --init

# 编译
tsc index.ts

# 使用ts-node直接运行
npm install -g ts-node
ts-node index.ts

# 项目中使用(Vite)
npm create vite@latest my-app -- --template vue-ts


三、基础类型

// ====================
// 基本类型
// ====================
let name: string = '张三'
let age: number = 25
let isActive: boolean = true
let nothing: null = null
let undef: undefined = undefined

// 数组
let numbers: number[] = [1, 2, 3]
let names: Array<string> = ['张三', '李四']

// 元组
let tuple: [string, number] = ['张三', 25]

// 枚举
enum Status {
  Pending = 'pending',
  Active = 'active',
  Disabled = 'disabled'
}
let status: Status = Status.Active

// any(任意类型,不推荐)
let data: any = 'hello'

// unknown(安全的any)
let input: unknown = 'hello'
if (typeof input === 'string') {
  console.log(input.toUpperCase())  // 需要类型检查
}

// void(无返回值)
function greet(): void {
  console.log('hello')
}

// never(永不返回)
function throwError(msg: string): never {
  throw new Error(msg)
}


四、接口与类型别名

// ====================
// 接口(Interface)
// ====================
interface User {
  id: number
  username: string
  email: string
  age?: number           // 可选属性
  readonly createdAt: Date  // 只读属性
}

const user: User = {
  id: 1,
  username: '张三',
  email: 'zhangsan@example.com',
  createdAt: new Date()
}

// 接口继承
interface Admin extends User {
  role: 'admin' | 'superadmin'
  permissions: string[]
}

// ====================
// 类型别名(Type)
// ====================
type ID = number | string

type UserRole = 'admin' | 'editor' | 'user'

type ApiResponse<T> = {
  code: number
  message: string
  data: T
}

// 使用
const userId: ID = 123
const role: UserRole = 'admin'
const response: ApiResponse<User> = {
  code: 200,
  message: 'success',
  data: user
}

// ====================
// 接口 vs 类型别名
// ====================
// 接口:可以extends和implements,可以声明合并
// 类型别名:可以定义联合类型、交叉类型、元组
// 推荐:对象用interface,其他用type


五、函数类型

// ====================
// 函数参数和返回值
// ====================
function add(a: number, b: number): number {
  return a + b
}

// 可选参数
function greet(name: string, greeting?: string): string {
  return `${greeting || 'Hello'}, ${name}!`
}

// 默认参数
function createUser(name: string, role: UserRole = 'user'): User {
  return { id: 1, username: name, email: '', createdAt: new Date() }
}

// 剩余参数
function sum(...numbers: number[]): number {
  return numbers.reduce((a, b) => a + b, 0)
}

// ====================
// 函数类型
// ====================
type MathFunc = (a: number, b: number) => number

const multiply: MathFunc = (a, b) => a * b
const divide: MathFunc = (a, b) => a / b

// ====================
// 函数重载
// ====================
function format(value: string): string
function format(value: number): string
function format(value: Date): string
function format(value: string | number | Date): string {
  if (typeof value === 'string') return value
  if (typeof value === 'number') return value.toFixed(2)
  return value.toISOString()
}


六、泛型

// ====================
// 泛型函数
// ====================
function identity<T>(arg: T): T {
  return arg
}

const num = identity<number>(123)      // number
const str = identity<string>('hello')  // string
const auto = identity('hello')         // 自动推断为string

// ====================
// 泛型接口
// ====================
interface ApiResponse<T> {
  code: number
  message: string
  data: T
}

interface PaginatedData<T> {
  items: T[]
  total: number
  page: number
  size: number
}

// 使用
const usersResponse: ApiResponse<PaginatedData<User>> = {
  code: 200,
  message: 'success',
  data: {
    items: [],
    total: 0,
    page: 1,
    size: 10
  }
}

// ====================
// 泛型约束
// ====================
interface HasId {
  id: number
}

function findById<T extends HasId>(items: T[], id: number): T | undefined {
  return items.find(item => item.id === id)
}

// ====================
// 泛型工具类型
// ====================
interface User {
  id: number
  username: string
  email: string
  password: string
}

// Partial:所有属性变为可选
type PartialUser = Partial<User>

// Required:所有属性变为必需
type RequiredUser = Required<PartialUser>

// Pick:选取部分属性
type UserBasic = Pick<User, 'id' | 'username'>

// Omit:排除部分属性
type UserWithoutPassword = Omit<User, 'password'>

// Record:构造键值对类型
type UserMap = Record<string, User>

// Exclude:从联合类型中排除
type StringOrNumber = string | number | boolean
type NotBoolean = Exclude<StringOrNumber, boolean>  // string | number

// ReturnType:获取函数返回类型
type GetUser = () => User
type GetUserReturn = ReturnType<GetUser>  // User


七、类

// ====================
// 类定义
// ====================
class User {
  // 属性声明
  public name: string
  private password: string
  protected email: string
  readonly id: number
  
  // 静态属性
  static count: number = 0
  
  // 构造函数
  constructor(id: number, name: string, email: string, password: string) {
    this.id = id
    this.name = name
    this.email = email
    this.password = password
    User.count++
  }
  
  // 方法
  public greet(): string {
    return `我是${this.name}`
  }
  
  // getter
  get displayName(): string {
    return this.name
  }
  
  // setter
  set displayName(value: string) {
    this.name = value
  }
  
  // 静态方法
  static getCount(): number {
    return User.count
  }
}

// ====================
// 继承
// ====================
class Admin extends User {
  role: string
  
  constructor(id: number, name: string, email: string, password: string, role: string) {
    super(id, name, email, password)
    this.role = role
  }
  
  greet(): string {
    return `${super.greet()}(${this.role})`
  }
}

// ====================
// 抽象类
// ====================
abstract class Shape {
  abstract area(): number
  abstract perimeter(): number
  
  describe(): string {
    return `面积: ${this.area().toFixed(2)}, 周长: ${this.perimeter().toFixed(2)}`
  }
}

class Circle extends Shape {
  constructor(private radius: number) {
    super()
  }
  
  area(): number {
    return Math.PI * this.radius ** 2
  }
  
  perimeter(): number {
    return 2 * Math.PI * this.radius
  }
}


八、React + TypeScript

// ====================
// 组件Props类型
// ====================
interface UserCardProps {
  user: User
  onEdit: (id: number) => void
  onDelete: (id: number) => void
  children?: React.ReactNode
}

function UserCard({ user, onEdit, onDelete, children }: UserCardProps) {
  return (
    <div>
      <h3>{user.username}</h3>
      <p>{user.email}</p>
      <button onClick={() => onEdit(user.id)}>编辑</button>
      <button onClick={() => onDelete(user.id)}>删除</button>
      {children}
    </div>
  )
}

// ====================
// useState 类型
// ====================
const [user, setUser] = useState<User | null>(null)
const [users, setUsers] = useState<User[]>([])
const [loading, setLoading] = useState<boolean>(false)
const [error, setError] = useState<string | null>(null)

// ====================
// useRef 类型
// ====================
const inputRef = useRef<HTMLInputElement>(null)
const canvasRef = useRef<HTMLCanvasElement>(null)

// ====================
// 事件处理
// ====================
const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
  console.log(e.currentTarget.value)
}

const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
  setValue(e.target.value)
}

const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
  e.preventDefault()
}

// ====================
// 自定义Hook类型
// ====================
interface UseFetchResult<T> {
  data: T | null
  loading: boolean
  error: string | null
  refetch: () => void
}

function useFetch<T>(url: string): UseFetchResult<T> {
  const [data, setData] = useState<T | null>(null)
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState<string | null>(null)
  
  const refetch = useCallback(async () => {
    setLoading(true)
    setError(null)
    try {
      const response = await fetch(url)
      const result = await response.json()
      setData(result)
    } catch (err) {
      setError(err instanceof Error ? err.message : '请求失败')
    } finally {
      setLoading(false)
    }
  }, [url])
  
  useEffect(() => { refetch() }, [refetch])
  
  return { data, loading, error, refetch }
}


九、Vue 3 + TypeScript

<script setup lang="ts">
import { ref, computed } from 'vue'

// 类型定义
interface User {
  id: number
  username: string
  email: string
}

// ref类型
const user = ref<User | null>(null)
const users = ref<User[]>([])
const loading = ref(false)

// computed类型
const userCount = computed<number>(() => users.value.length)

// Props类型
interface Props {
  title: string
  users: User[]
  loading?: boolean
}

const props = withDefaults(defineProps<Props>(), {
  loading: false
})

// Emits类型
const emit = defineEmits<{
  (e: 'update', id: number): void
  (e: 'delete', id: number): void
}>()

// 函数类型
const fetchUser = async (id: number): Promise<User> => {
  const response = await fetch(`/api/users/${id}`)
  return response.json()
}
</script>


十、常见模式

// ====================
// API请求封装
// ====================
class ApiClient {
  constructor(private baseUrl: string) {}
  
  async get<T>(path: string): Promise<ApiResponse<T>> {
    const response = await fetch(`${this.baseUrl}${path}`)
    return response.json()
  }
  
  async post<T>(path: string, data: unknown): Promise<ApiResponse<T>> {
    const response = await fetch(`${this.baseUrl}${path}`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(data)
    })
    return response.json()
  }
}

const api = new ApiClient('/api')
const { data: users } = await api.get<User[]>('/users')

// ====================
// 类型守卫
// ====================
function isUser(obj: unknown): obj is User {
  return typeof obj === 'object' && obj !== null && 'username' in obj
}

// ====================
// 映射类型
// ====================
type Readonly<T> = {
  readonly [P in keyof T]: T[P]
}

type Optional<T> = {
  [P in keyof T]?: T[P]
}


学习建议

  1. 先掌握基础类型,理解string/number/boolean/array/object
  2. 学习接口和类型别名,这是定义数据结构的核心
  3. 理解泛型,提高代码复用性
  4. 在实际项目中使用,Vue/React + TypeScript是主流
  5. 不要过度类型化,简单的地方让TS自动推断

下一步学习

返回首页