何为“完全在类型系统内实现功能”?TypeScript Flappy Bird实现解惑
TypeScript的类型系统虽然主打静态类型检查,但它具备图灵完备性——通过组合递归类型、条件类型、映射类型等特性,完全可以模拟程序的逻辑计算流程,这就是在类型系统内实现Flappy Bird的核心基础。具体实现逻辑可拆解为以下几点:
用类型模拟游戏核心状态
游戏里的所有关键状态(小鸟的Y坐标、管道的X坐标、当前得分、游戏是否结束)都用TypeScript类型来表示,比如用元组类型[BirdY: number, PipeX: number, Score: number, IsGameOver: boolean]存储单帧游戏状态。初始状态、每帧的状态更新都通过类型推导完成。用类型函数处理游戏逻辑
把游戏的核心逻辑(跳跃、管道移动、碰撞检测、得分计算)转化为类型层面的函数:- 比如
Jump<State>类型:接收当前状态类型,通过条件类型计算小鸟跳跃后的Y坐标(比如原坐标减固定值),同时让管道X坐标左移,生成新的状态类型。 - 碰撞检测则通过条件类型判断小鸟坐标是否和管道坐标重叠,如果重叠就将
IsGameOver设为true。
- 比如
递归类型实现游戏循环
利用TypeScript对递归类型的支持,实现类似帧循环的逻辑。比如定义GameLoop<State, Inputs>类型:遍历输入序列(比如['jump', 'no-op', 'no-op']代表连续的操作),每次处理一个输入,推导出新的状态,再递归处理下一个输入,直到所有输入处理完毕,最终输出最终的游戏状态。示例代码大致如下:type UpdateState<State, Input> = Input extends 'jump' ? // 处理跳跃逻辑,返回新状态 State extends [infer Y, infer X, infer S, infer O] ? [Y extends number ? Y - 10 : Y, X extends number ? X - 5 : X, S, O] : State : // 处理无操作逻辑,管道左移+得分判断 State extends [infer Y, infer X, infer S, infer O] ? [Y, X extends number ? X - 5 : X, X extends 0 ? S extends number ? S + 1 : S : S, O] : State; type GameLoop<State, Inputs extends any[]> = Inputs extends [infer First, ...infer Rest] ? GameLoop<UpdateState<State, First>, Rest> : State; // 初始状态:小鸟Y=50,管道X=100,得分0,未结束 type InitialState = [50, 100, 0, false]; // 模拟操作:跳跃、无操作、无操作 type FinalState = GameLoop<InitialState, ['jump', 'no-op', 'no-op']>;把鼠标悬停在
FinalState上,就能看到推导后的最终游戏状态。通过类型推导结果呈现游戏进程
这种实现没有任何运行时的动画或交互,所有“游戏过程”都通过TypeScript编辑器的类型提示来呈现——用户通过查看类型别名的推导结果,就能看到小鸟位置、得分的变化,以及游戏是否结束。
本质上,这是把游戏逻辑完全转化为静态的类型规则推导,所有计算都在TypeScript的类型检查阶段完成,完全不需要执行任何运行时代码。
内容的提问来源于stack exchange,提问作者Yusuf Bouzekri

