TypeScript 基础(上):基础类型与接口

好,咱们开始进入 TypeScript 的核心部分。说实话,很多同学学 TypeScript 容易卡在「类型体操」上,但我觉得,先把基础类型和接口玩明白,日常开发就够用了。今天这一章,我带你把这些基础打扎实。

基础类型:number、string、boolean、array、object

TypeScript 的基础类型,说白了就是给 JavaScript 的值加了个「标签」。你想想看,JS 里一个变量可以是数字、字符串、对象,但到底是个啥,得运行了才知道。TypeScript 就是要让这些信息在写代码的时候就明确下来。

number、string、boolean

这三个是最常用的基础类型。写法很简单:

let age: number = 28;
let name: string = '张三';
let isActive: boolean = true;

嗯,这里要注意:number 不区分整数和浮点数,所有数字都是 number 类型。我在项目中遇到过有人写 let count: int = 5,结果 TypeScript 直接报错——没有 int 类型,只有 number

小技巧: 如果你想让代码更简洁,其实可以省略类型注解。TypeScript 会自动推断类型。比如 let age = 28,它就知道 age 是 number 类型。

array 数组

数组有两种写法,我个人习惯用第一种:

// 写法一:推荐
let list: number[] = [1, 2, 3];

// 写法二:泛型写法
let list2: Array<number> = [1, 2, 3];

为什么推荐第一种?因为更直观。你一眼就能看出这是个数字数组。第二种在 JSX 里容易和 HTML 标签混淆,我踩过这个坑。

object 对象类型

对象类型稍微复杂一点。你不能只写 let obj: object = {},这样 TypeScript 只知道它是一个对象,但不知道里面有什么属性。正确的做法是:

let user: { name: string; age: number } = {
  name: '李四',
  age: 25
};

但说实话,这种写法在项目中很少直接用。因为一旦对象结构复杂了,代码会变得又长又丑。这时候就需要接口(interface)出场了。

类型注解与类型推断

这两个概念是 TypeScript 的基石。我简单解释一下:

  • 类型注解:你主动告诉 TypeScript 某个变量是什么类型。
  • 类型推断:TypeScript 根据赋值自动推导出类型。

举个例子:

// 类型注解
let count: number = 10;

// 类型推断
let count2 = 10; // TypeScript 自动推断为 number

我个人建议:能用推断的就别写注解。比如 let count = 10 已经很清楚是数字了,再加 : number 就是画蛇添足。但函数参数和返回值,我建议显式注解,因为这是「接口契约」,别人调用你的函数时能一眼看懂。

核心原则: 类型推断能省则省,函数边界显式标注。

我曾经在团队里推行过「能不写就不写」的原则,结果代码 review 时发现有人把 let x: any = 'hello' 写得到处都是。any 类型会关闭类型检查,说白了就是「自废武功」。所以,尽量避免 any

接口(interface)的基本使用

接口是 TypeScript 里我最喜欢的功能之一。它就像一份「合同」,规定了对象应该长什么样。

定义接口

interface User {
  name: string;
  age: number;
  email?: string; // 可选属性
  readonly id: number; // 只读属性
}

这里我解释一下:

  • email? 表示这个属性可有可无。我在项目中经常用可选属性来处理「有些字段不一定有」的情况。
  • readonly id 表示这个属性只能在创建时赋值,之后不能修改。比如用户 ID,一旦创建就不应该变。

使用接口

function greet(user: User): string {
  return `你好,${user.name}!`;
}

const newUser: User = {
  name: '王五',
  age: 30,
  id: 1001
};

console.log(greet(newUser)); // 输出:你好,王五!

你想想看,如果没有接口,这个函数参数的类型得写成 { name: string; age: number; email?: string; readonly id: number },多长啊。用接口一封装,代码瞬间清爽了。

避坑指南: 我曾经在项目中把接口定义在组件文件里,结果多个组件都要用,到处 import。后来我把所有接口统一放到 types.ts 文件里,管理起来方便多了。建议你也这么做。

接口的扩展

接口可以继承,就像类一样:

interface Admin extends User {
  role: 'admin' | 'superadmin';
  permissions: string[];
}

const adminUser: Admin = {
  name: '赵六',
  age: 35,
  id: 2001,
  role: 'admin',
  permissions: ['read', 'write', 'delete']
};

这样,Admin 就拥有了 User 的所有属性,还多了自己的专属属性。我在做后台管理系统时,经常用这种方式来区分普通用户和管理员。

类型 vs 接口:什么时候用哪个?

很多新手会纠结这个问题。我直接给你一个实用建议:

场景 推荐用 原因
定义对象结构 interface 更直观,支持扩展
定义联合类型或交叉类型 type type 更灵活
定义函数类型 type 写法更简洁
需要合并声明 interface interface 支持声明合并

说白了,能用 interface 就用 interface,搞不定的时候再上 type。这是我在实际项目中总结出来的经验。

小结

这一章我们聊了 TypeScript 的基础类型、类型注解与推断,还有接口的基本使用。记住几个关键点:

  • 基础类型要记牢,但别过度注解
  • 接口是定义对象结构的利器
  • 能用 interface 就别用 type(大部分情况)
  • 避免 any,保持类型安全

下一章我们会深入接口的高级用法,比如泛型接口、接口与类的结合。到时候你会发现,TypeScript 的类型系统比想象中强大得多。

课后练习: 定义一个 Product 接口,包含 id、name、price、description(可选)、category(只读)。然后写一个函数,接收 Product 类型参数,返回格式化后的商品信息字符串。

好,今天就到这里。有什么问题欢迎在评论区交流,咱们下章见。