You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现带编译期校验的TypeScript状态机?

TypeScript 编译期强制校验的状态机实现方案

需求说明

想要实现一个由TypeScript编译器强制校验状态转换的状态机,期望的定义方式如下:

type States = {
    state1: {state: 'state1'},
    state2: {state: 'state2'}
}

const Transitions: TransitionsType<States> = {
    init() {
        return {state: 'state1'}
    },
    state1: {
        state2({...anyOtherItems}) {
            // 处理额外数据
            return {...anyOtherItems, state: 'state2'}
        }
    },
    state2: {
        state1({...others}) {
            return {state: 'state1'}
        }
    }
};

transition(Transitions, {state: 'state1'}, 'state2');

核心需求:

  • States类型描述每个状态对应的数据结构
  • Transitions对象以源状态为第一层键,目标状态为第二层键,转换函数接收源状态类型参数,返回目标状态类型参数;init函数负责初始化状态
  • 当转换函数返回错误的状态对象,或者调用transition时传入非法的状态转换组合,编译器必须抛出错误

现有实现的问题

当前代码存在两个关键问题:

  1. return toTransition(state);行出现编译错误,因为TypeScript无法推断toTransition的参数和返回值类型匹配
  2. 调用transition传入非法转换(比如从state1到不存在的state3)时,编译器不会报错

修正后的实现方案

下面是可以满足需求的完整实现:

类型定义部分

// 确保每个状态对象都包含对应的state字面量类型
type StateObject<State extends string> = { state: State };

// 定义状态机的状态映射:键是状态名,值是对应状态对象类型
type StateMap = { [K in string]: StateObject<K> };

// 单个源状态下的所有合法转换:键是目标状态名,值是转换函数
type StateTransitions<S extends StateMap, From extends keyof S> = {
  [To in keyof S]?: (currentState: S[From]) => S[To];
};

// 完整的状态转换配置类型
type TransitionsType<S extends StateMap> = {
  [From in keyof S]: StateTransitions<S, From>;
} & {
  init: () => S[keyof S];
};

核心transition函数实现

// 利用泛型约束,让编译器在编译期检查转换合法性
function transition<
  S extends StateMap,
  From extends keyof S,
  To extends keyof S
>(
  transitions: TransitionsType<S>,
  currentState: S[From],
  to: To
): S[To] {
  const fromTransitions = transitions[currentState.state];
  const transitionFn = fromTransitions?.[to];

  if (!transitionFn) {
    throw new TypeError(`不存在从 ${currentState.state} 到 ${String(to)} 的转换`);
  }

  // 这里类型完全匹配,不会有编译错误
  return transitionFn(currentState);
}

效果验证

用之前的States和Transitions测试:

  1. 如果转换函数返回错误的状态(比如state1的state2函数返回{state: 'state1'}),编译器会直接报错,因为返回值类型不匹配S['state2']
  2. 如果调用transition(Transitions, {state: 'state1'}, 'state3'),编译器会报错,因为state3不是States的合法键,且Transitions中没有对应的转换定义
  3. transition函数的返回值类型会被正确推断为目标状态的类型,比如transition(Transitions, {state: 'state1'}, 'state2')的返回值类型是States['state2']

关键改进点

  • 用更精确的泛型参数From和To,让编译器能追踪当前状态和目标状态的类型
  • 约束transition函数的currentState必须是S[From],to必须是keyof S,同时确保转换函数的参数和返回值类型严格对应
  • 消除了原代码中的类型断言,让类型推导完全由编译器自动完成

内容的提问来源于stack exchange,提问作者Rahul D'Souza

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 22:50:36