← 编程学习中心
📖

Preparation

8 个课程
1
如何学习编程
2
计算机基础
3
键盘初识与基准键位
4
字母与数字基础
5
Shift键魔法
6
编程符号专精
7
功能键与修饰键
8
键盘学习总结与进阶
📚

Basics

22 个课程
1
什么是编程?
2
Hello World - 你的第一个程序
3
变量基础概念 - 给信息贴标签
4
变量赋值和操作 - 变量的高级用法
5
数据类型基础 - 数字和字符串
6
基础运算符 - 数字运算王国
7
布尔类型与比较运算符 - 程序的判断基础
8
条件判断基础 - 让程序学会做决定
9
变量作用域 - 变量的生存范围
10
条件语句进阶 - 复杂判断与嵌套结构
11
逻辑运算符 - 简化复杂条件判断
12
循环语句 - 程序的重复机器
13
循环进阶 - break、continue与循环控制
14
嵌套循环与作用域
15
循环调试实战技巧
16
循环不变量 - 理解循环的数学规律
17
数组基础 - 数据的收纳盒
18
数组操作方法 - 添加、删除和管理
19
数组高级 - 探索数组的强大功能
20
引用概念 - 变量的不同行为
21
函数基础 - 解决重复代码的秘密武器
22
函数实践与应用 - 巩固基础,实战应用
🚀

Intermediate

11 个课程
1
从控制台到画布 - p5.js初体验
2
图形绘制工具箱 - 基础图形函数
3
让世界多彩 - 颜色系统详解
4
文字的艺术 - 文本绘制与样式
5
球体动起来 - 动画基础入门
6
球体的交互魔法 - 鼠标与条件判断
7
面向对象编程 - Class类与实例
8
球的家族 - 循环与数组应用
9
球的个性 - 函数封装与参数化
10
球的变身 - 形状模式与高级绘制
11
球的世界 - 综合创作项目
🎯

Advanced

6 个课程
1
对象类型
2
对象类型应用
3
自定义类型
4
函数进阶 - 箭头函数与高级编程技巧
5
内置方法 - 字符串与数组的魔法工具
6
Switch语句与字符串模板 - 更优雅的代码表达
← 编程学习中心
📖

Preparation

8 个课程
1
如何学习编程
2
计算机基础
3
键盘初识与基准键位
4
字母与数字基础
5
Shift键魔法
6
编程符号专精
7
功能键与修饰键
8
键盘学习总结与进阶
📚

Basics

22 个课程
1
什么是编程?
2
Hello World - 你的第一个程序
3
变量基础概念 - 给信息贴标签
4
变量赋值和操作 - 变量的高级用法
5
数据类型基础 - 数字和字符串
6
基础运算符 - 数字运算王国
7
布尔类型与比较运算符 - 程序的判断基础
8
条件判断基础 - 让程序学会做决定
9
变量作用域 - 变量的生存范围
10
条件语句进阶 - 复杂判断与嵌套结构
11
逻辑运算符 - 简化复杂条件判断
12
循环语句 - 程序的重复机器
13
循环进阶 - break、continue与循环控制
14
嵌套循环与作用域
15
循环调试实战技巧
16
循环不变量 - 理解循环的数学规律
17
数组基础 - 数据的收纳盒
18
数组操作方法 - 添加、删除和管理
19
数组高级 - 探索数组的强大功能
20
引用概念 - 变量的不同行为
21
函数基础 - 解决重复代码的秘密武器
22
函数实践与应用 - 巩固基础,实战应用
🚀

Intermediate

11 个课程
1
从控制台到画布 - p5.js初体验
2
图形绘制工具箱 - 基础图形函数
3
让世界多彩 - 颜色系统详解
4
文字的艺术 - 文本绘制与样式
5
球体动起来 - 动画基础入门
6
球体的交互魔法 - 鼠标与条件判断
7
面向对象编程 - Class类与实例
8
球的家族 - 循环与数组应用
9
球的个性 - 函数封装与参数化
10
球的变身 - 形状模式与高级绘制
11
球的世界 - 综合创作项目
🎯

Advanced

6 个课程
1
对象类型
2
对象类型应用
3
自定义类型
4
函数进阶 - 箭头函数与高级编程技巧
5
内置方法 - 字符串与数组的魔法工具
6
Switch语句与字符串模板 - 更优雅的代码表达

自定义类型

为什么需要自定义类型?

在上一课《对象类型应用》中,我们学习了如何在函数中使用对象类型。我们学会了手动指定函数的参数和返回值类型,比如:

加载代码编辑器...

这种方法很好!它给了我们类型安全。但是,当我们的项目变得更大,需要创建更多相关的函数时,新的问题就出现了。

问题1:类型重复的困扰

现在假设我们要添加更多处理角色的函数:

加载代码编辑器...

看出了什么问题吗?

我们在每个函数中都重复了完全相同的对象类型定义:

加载代码编辑器...

这让代码变得很长,难以阅读!

问题2:维护的噩梦

现在想象一下,如果我们要给角色添加一个新属性,比如 mana(魔法值)。我们必须修改每一个函数的类型定义:

加载代码编辑器...

想象一下:

  • 如果有 10 个这样的函数,就需要修改 20 处(参数类型 + 返回值类型)
  • 每次修改都可能出错,忘记某个地方

问题3:代码可读性差

当你看到这样的函数签名时,需要花时间才能理解:

加载代码编辑器...

这到底是处理什么类型的对象? 你需要仔细阅读整个类型定义才能明白。

有没有更好的方法呢?

更好的解决方案:给类型起个名字

既然我们都想要创建相同的对象结构,为什么不给这个结构起一个名字呢?

这就是 TypeScript 中 自定义类型 的作用!

加载代码编辑器...

现在我们可以重写所有的函数:

加载代码编辑器...

看看这些改进:

  1. 代码更简洁:不需要每次都写长长的对象类型定义
  2. 更易维护:如果要添加新属性,只需要修改 Character 类型定义
  3. 不易出错:TypeScript 会确保所有使用 Character 类型的函数都返回正确的结构

自定义类型的威力

现在如果我们想要给角色添加 mana(魔法值)属性,只需要修改一个地方:

加载代码编辑器...

TypeScript 会自动检查所有使用 Character 类型的函数,提醒我们在需要的地方更新代码:

加载代码编辑器...

自定义类型的核心优势

通过上面的例子,我们看到了自定义类型的核心优势:

  1. 定义一次,使用处处:避免了类型定义的重复
  2. 维护简单:修改类型只需要改一个地方
  3. 类型安全:确保所有地方使用的是相同的类型
  4. 代码清晰:Character 比复杂的内联类型更容易理解
  5. 团队协作:团队成员都能清楚地知道数据结构

这就是为什么我们需要自定义类型!它解决了类型推断的局限性,同时避免了手动指定类型的重复和混乱。

类型定义的详细语法

让我们详细分析这个类型定义:

加载代码编辑器...

语法结构解析:

  1. type 关键字 - 表示"我要定义一个新的类型"
  2. Character - 类型名称,必须大写字母开头(PascalCase)
  3. = - 赋值符号,把右边的结构赋值给类型名称
  4. {} - 对象类型标记,表示这是一个对象结构
  5. name: string; - 属性定义
    • name 是属性名
    • : 是分隔符
    • string 是属性类型
    • ; 结尾符(每个属性都必须以分号结尾)

手动声明 vs 类型推断的对比

加载代码编辑器...

我们为什么强烈推荐手动声明类型?

  1. 代码清晰:一看就知道每个变量应该有什么属性
  2. 团队协作:团队成员都能清楚地知道数据结构
  3. 错误预防:拼写错误会立即被发现
  4. 文档作用:类型定义本身就是最好的文档
  5. 重构友好:修改类型时,所有相关代码都会被检查

最佳实践:总是使用 type 声明类型

加载代码编辑器...

记住:在实际项目中,总是先用 type 定义好数据结构,然后创建符合该类型的变量。

类型检查和错误示例

当我们使用自定义类型时,TypeScript 会提供强大的类型检查。让我们看看常见的错误:

错误示例 1:缺少必需属性

加载代码编辑器...

错误解释:

  • Character 类型要求必须有 name、level、health 三个属性
  • 但你只提供了 name 和 level
  • TypeScript 提醒你补充缺少的 health 属性

错误示例 2:属性类型不匹配

加载代码编辑器...

错误解释:

  • Character 类型定义 level 必须是 number(数字)
  • 但你给 level 赋值了 "低等级",这是一个 string(字符串)
  • TypeScript 不允许类型不匹配的赋值

错误示例 3:多余的字段

加载代码编辑器...

错误解释:

  • Character 类型只定义了 name、level、health 三个属性
  • 但你创建的对象包含了额外的 mana 属性
  • TypeScript 要求对象只能包含类型定义中明确声明的属性

为什么有这个限制?

  • 类型安全:确保代码中使用的属性都是明确定义的
  • 避免拼写错误:防止因为属性名拼写错误导致的 bug
  • 代码清晰:让代码更容易理解和维护

如何处理这些错误?

如果缺少属性,补充必需的属性:

加载代码编辑器...

如果类型不匹配,使用正确的类型:

加载代码编辑器...

如果需要更多属性,更新类型定义:

加载代码编辑器...

函数与自定义类型

自定义类型的真正威力体现在函数中!

函数接受对象参数

加载代码编辑器...

函数返回对象类型

加载代码编辑器...

为什么函数中使用自定义类型很有用?

  1. 类型安全:函数只接受符合类型要求的参数
  2. 代码提示:编辑器会提示有哪些属性可用
  3. 错误预防:TypeScript 会在编译时发现参数类型错误
  4. 代码清晰:函数签名清楚地说明了期望什么样的参数

数组中的自定义类型

我们可以创建包含自定义类型对象的数组:

加载代码编辑器...

实际项目中的类型组织

在真实的项目中,我们通常会组织多个相关的类型:

加载代码编辑器...

类型名称的命名规范

良好的命名规范让代码更易读:

加载代码编辑器...

命名规范要点:

  1. 大写字母开头(PascalCase)
  2. 名称描述性强:能清楚地表达类型的作用
  3. 避免缩写:除非是广为人知的缩写(如 ID、URL)
  4. 使用完整单词:Player 比 Plr 更好

总结

通过这节课,我们学习了:

  1. 自定义类型的必要性:解决类型推断的问题
  2. type 关键字语法:如何定义自定义类型
  3. 类型检查机制:TypeScript 如何检查类型错误
  4. 错误处理:如何识别和修复类型错误
  5. 函数中的应用:参数和返回值类型
  6. 数组中的应用:类型数组的创建和使用
  7. 实际项目应用:类型组织和命名规范

重要记住:

  • 总是使用 type 手动声明类型
  • 类型名称必须大写字母开头
  • 属性定义必须以分号结尾
  • TypeScript 关注结构,不关注名称
  • 明确定义类型比依赖推断更好

自定义类型是 TypeScript 的核心特性,掌握它将帮助你写出更安全、更清晰、更易维护的代码!

Previous lesson
Previous
对象类型应用
Next
函数进阶 - 箭头函数与高级编程技巧
Next lesson