快速回顾TypeScript基础知识

106 阅读5分钟

什么是 TypeScript?为什么要用它?

TypeScript(简称 TS)是 JavaScript 的超集,由微软开发并维护。它在 JavaScript 的基础上增加了静态类型系统,让我们能在代码运行前就发现错误,大幅提升代码质量和开发效率。

为什么选择 TypeScript?

  • 类型安全:提前捕获错误,减少运行时 bug

  • 更好的 IDE 支持:自动补全、接口提示、重构工具

  • 代码可维护性:类型定义本身就是最好的文档

  • 渐进式采用:可以逐步将 JS 项目迁移到 TS

  • 大型项目友好:适合团队协作和长期维护

适合人群:有 JavaScript 基础,想提升代码质量的开发者

快速开始:环境搭建

安装 TypeScript

# 全局安装TypeScript编译器
npm install -g typescript

# 检查安装是否成功
tsc --version

第一个 TypeScript 程序

  1. 创建hello.ts文件:

function greet(name: string): string {
  return `Hello, ${name}!`;
}

const message = greet("TypeScript");
console.log(message);
  1. 编译 TS 为 JS:

tsc hello.ts  # 会生成hello.js文件
  1. 运行结果:

node hello.js  # 输出:Hello, TypeScript!

推荐开发工具

  • VS Code:内置 TypeScript 支持,体验最佳
  • WebStorm:优秀的 TypeScript 集成
  • 配置自动编译:创建tsconfig.json文件,使用tsc --watch自动监听文件变化

核心语法快速掌握

1. 基础类型系统

TypeScript 的类型系统是可选的,你可以根据需要逐步添加类型注解。

// 原始类型
let age: number = 25;           // 数字
let name: string = "张三";      // 字符串
let isStudent: boolean = true;  // 布尔值
let u: undefined = undefined;   // 未定义
let n: null = null;             // 空值

// 任意类型 - 临时绕过类型检查
let anyValue: any = "hello";
anyValue = 123;                // 合法
anyValue = true;               // 合法

// 未知类型 - 更安全的any
let unknownValue: unknown = "test";
// unknown类型需要先断言才能使用
if (typeof unknownValue === "string") {
  console.log(unknownValue.length);  // 合法
}

实战技巧:尽量避免使用any,优先使用更具体的类型或unknown

2. 复合类型

// 数组类型 - 两种声明方式
let numbers: number[] = [1, 2, 3];
let strings: Array<string> = ["a", "b", "c"];

// 元组 - 固定长度和类型的数组
let user: [string, number] = ["张三", 25];  // [姓名, 年龄]
let [userName, userAge] = user;            // 解构赋值

// 对象类型
let person: { name: string; age: number } = {
  name: "李四",
  age: 30
};

实战应用:元组非常适合表示有固定结构的数据,如[x, y]坐标、[label, value]键值对等

3. 接口(Interface)

接口用于描述对象的形状,是 TypeScript 中最强大的特性之一。

// 基本用法
interface User {
  id: number;             // 必选属性
  name: string;           // 必选属性
  age?: number;           // 可选属性(?表示)
  readonly email: string; // 只读属性
}

// 实现接口
const user1: User = {
  id: 1,
  name: "王五",
  email: "wangwu@example.com"
  // age可选,可以不提供
};

// 接口扩展 - 继承其他接口
interface Employee extends User {
  department: string;
  salary: number;
}

const emp: Employee = {
  id: 2,
  name: "赵六",
  email: "zhaoliu@example.com",
  department: "开发部",
  salary: 10000
};

实战技巧

  • 用接口定义数据模型和组件 Props
  • 接口名建议使用大驼峰命名法(如UserInfo
  • 合理使用readonly保护不应该被修改的数据

4. 函数类型

TypeScript 可以为函数参数和返回值指定类型。

// 函数声明
function add(a: number, b: number): number {
  return a + b;
}

// 可选参数 - 必须放在最后
function greet(name: string, title?: string): string {
  if (title) {
    return `Hello, ${title} ${name}`;
  }
  return `Hello, ${name}`;
}

// 默认参数
function multiply(a: number, b: number = 1): number {
  return a * b;
}

// 函数表达式
const divide: (a: number, b: number) => number = (a, b) => {
  return a / b;
};

实战应用

  • 为工具函数添加完整类型注解
  • 使用函数类型定义回调函数接口
  • 复杂函数优先使用函数声明式,便于类型推断

5. 类型特性

类型推论

TypeScript 会自动推断未明确指定的类型:

let message = "hello";  // 自动推断为string类型
// message = 123;      // 错误:不能将number赋值给string

联合类型

一个变量可以是多种类型中的一种:

let result: string | number;
result = "success";  // 合法
result = 100;        // 合法

// 类型收窄 - 缩小类型范围
function getValueLength(value: string | number): number {
  if (typeof value === "string") {
    return value.length;  // 此处TypeScript知道value是string
  }
  return value.toString().length;  // 此处知道是number
}

类型断言

告诉 TypeScript 你比它更了解变量的类型:

// 两种语法
const input: unknown = "hello world";
const strLength1 = (input as string).length;
const strLength2 = (<string>input).length;  // JSX中不推荐

实战技巧

  • 优先使用类型收窄(typeofinstanceof等)而非类型断言
  • 类型断言不能改变变量的实际类型,只是欺骗编译器

6. 枚举(Enums)

枚举用于定义命名常量集合,提高代码可读性。

// 数字枚举
enum StatusCode {
  Success = 200,
  NotFound = 404,
  ServerError = 500
}

console.log(StatusCode.Success);  // 输出:200

// 字符串枚举
enum Direction {
  Up = "UP",
  Down = "DOWN",
  Left = "LEFT",
  Right = "RIGHT"
}

// 使用枚举
function move(direction: Direction): void {
  console.log(`Moving ${direction}`);
}

move(Direction.Up);  // 输出:Moving UP

实战应用

  • 用枚举表示状态码、错误类型、方向等固定值集合
  • 优先使用字符串枚举,更具可读性和调试友好性
  • 不需要反向映射时,使用const enum提升性能

7. 泛型(Generics)

泛型是创建可复用组件的工具,让组件可以支持多种类型。

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

// 使用时指定类型
const num = identity<number>(10);
const str = identity<string>("hello");

// 泛型类
class Box<T> {
  private value: T;
  
  constructor(value: T) {
    this.value = value;
  }
  
  getValue(): T {
    return this.value;
  }
}

const numberBox = new Box<number>(100);
const stringBox = new Box<string>("test");

// 泛型约束
interface HasLength {
  length: number;
}

function getLength<T extends HasLength>(item: T): number {
  return item.length;
}

getLength("hello");  // 正确:string有length属性
getLength([1, 2, 3]);  // 正确:数组有length属性

实战应用

  • 用泛型创建可复用的数据结构(如列表、栈、队列)
  • React 组件中常用泛型定义 Props 和 State 类型
  • 使用泛型约束确保类型安全

实战应用指南

1. 项目配置(tsconfig.json)

创建tsconfig.json配置文件,定制 TypeScript 编译选项:

{
  "compilerOptions": {
    "target": "ES6",          // 编译目标ES版本
    "module": "ESNext",       // 模块系统
    "outDir": "./dist",       // 输出目录
    "rootDir": "./src",       // 源文件目录
    "strict": true,           // 开启严格模式
    "esModuleInterop": true,  // 兼容CommonJS和ES模块
    "skipLibCheck": true,     // 跳过库类型检查
    "forceConsistentCasingInFileNames": true
  },
  "include": ["src/**/*"],    // 需要编译的文件
  "exclude": ["node_modules"] // 排除的文件
}

推荐设置:开启strict: true以获得最佳类型检查体验

2. 与 JavaScript 项目共存

可以逐步将 JavaScript 项目迁移到 TypeScript:

  1. .js文件重命名为.ts
  2. 逐个添加类型注解
  3. 使用// @ts-ignore临时忽略类型错误(谨慎使用)
  4. 创建globals.d.ts声明全局类型

3. 处理第三方库

大部分流行库都有类型定义文件(.d.ts):

# 安装库的类型定义
npm install --save-dev @types/lodash  # 安装lodash的类型定义

如果没有类型定义,可以自己创建:

// 声明一个没有类型定义的模块
declare module "some-library" {
  export function doSomething(): void;
  export const version: string;
}

4. 常用开发技巧

  1. 类型别名:给复杂类型起别名

type UserID = string | number;
type ApiResponse<T> = {
  success: boolean;
  data: T;
  error?: string;
};

// 使用
const response: ApiResponse<User> = {
  success: true,
  data: { id: 1, name: "张三" }
};
  1. 交叉类型:合并多个类型

type WithId = { id: number };
type WithName = { name: string };
type Entity = WithId & WithName;  // { id: number; name: string }
  1. 类型守卫:自定义类型检查函数

interface Cat {
  meow: () => void;
}

interface Dog {
  bark: () => void;
}

// 类型守卫函数
function isCat(animal: Cat | Dog): animal is Cat {
  return "meow" in animal;
}

function makeSound(animal: Cat | Dog) {
  if (isCat(animal)) {
    animal.meow();  // TypeScript知道这是Cat
  } else {
    animal.bark();  // TypeScript知道这是Dog
  }
}

5. 在框架中使用

React + TypeScript

import React, { useState } from 'react';

// 定义Props类型
interface GreetingProps {
  name: string;
  age?: number;  // 可选属性
}

// 带类型的组件
const Greeting: React.FC<GreetingProps> = ({ name, age }) => {
  const [message, setMessage] = useState<string>("Hello");
  
  return (
    <div>
      {message}, {name}
      {age && <span> (Age: {age})</span>}
    </div>
  );
};

Vue + TypeScript

<script lang="ts">
import { defineComponent, ref } from 'vue';

interface User {
  name: string;
  age: number;
}

export default defineComponent({
  name: 'UserProfile',
  props: {
    user: {
      type: Object as () => User,
      required: true
    }
  },
  setup(props) {
    const message = ref<string>('Hello');
    
    return {
      message
    };
  }
});
</script>

更深入的学习

推荐资源

继续学习

  1. 熟练掌握高级类型(映射类型、条件类型等)
  2. 学习 TypeScript 与常用前端框架的结合
  3. 掌握类型声明文件的编写
  4. 在实际项目中逐步应用 TypeScript

总结

TypeScript 虽然有一定学习成本,但带来的收益远超投入。它能帮助你:

  • 减少 80% 的类型相关 bug
  • 提高代码可读性和可维护性
  • 改善团队协作效率
  • 获得更好的开发体验