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

使用泛型自引用静态类型化状态机的状态键

问题描述

我为聊天机器人自动化库开发了有限状态机助手,用于引导用户完成对话的不同阶段。目前功能正常,但想优化静态类型体验:当用户通过状态机描述符创建状态机时,stateMachine.setState()方法只能接受描述符里定义的状态键(比如示例中的"state1"|"state2"),不能是任意字符串。

当前类型定义里StateId设为string,导致setState参数类型太宽。试过多种方案都报TypeScript错误,只能暂时用字符串类型,求正确的泛型实现方式。

当前类型定义:

type StateId = string;

type State =
    {
        onMessage: (
            requester: MessageObj,
            stateMachineInstance: StateMachineInstance
        ) => any;
    }

type StateMachineDescriptor = {
    initialState: StateId;
    states: {
        [stateId: string]: State,
    }
};

type StateMachineInstance = StateMachineDescriptor & {
    currentState: StateId;
    setState: (newState: StateId) => void;
    reset: () => void;
};

期望的使用示例:

const myStateMachine = createStateMachine({
    initialState: "state1",
    states: {
        state1: {
            onMessage: (requester: MessageObj, stateMachine: StateMachineInstance) => {
                requester.reply("hello1");
                stateMachine.setState("state2");
            }
        },
        state2: {
            onMessage: (requester: MessageObj, stateMachine: StateMachineInstance) => {
                requester.reply("hello2");
                stateMachine.setState("state1");
            }
        }
    }
});
解决方案

核心是用泛型捕获状态机描述符里的状态键类型,让setState的参数类型自动约束为这些键的联合类型。具体改造步骤如下:

  1. 给StateMachineDescriptor添加泛型参数S extends string,用来表示状态键的类型:
type StateMachineDescriptor<S extends string> = {
    initialState: S;
    states: Record<S, State<S>>;
};
  1. 改造State类型,同样引入泛型S,让onMessage里的stateMachineInstance类型绑定当前状态机的状态键:
type State<S extends string> = {
    onMessage: (
        requester: MessageObj,
        stateMachineInstance: StateMachineInstance<S>
    ) => any;
};
  1. 调整StateMachineInstance的泛型定义,让currentState和setState的参数都约束为S:
type StateMachineInstance<S extends string> = StateMachineDescriptor<S> & {
    currentState: S;
    setState: (newState: S) => void;
    reset: () => void;
};
  1. 最后给createStateMachine函数添加泛型推导,让TypeScript自动从传入的描述符中推断出状态键类型:
function createStateMachine<S extends string>(descriptor: StateMachineDescriptor<S>): StateMachineInstance<S> {
    // 状态机实例实现逻辑,这里给出基础示例
    return {
        ...descriptor,
        currentState: descriptor.initialState,
        setState(newState) {
            this.currentState = newState;
        },
        reset() {
            this.currentState = descriptor.initialState;
        }
    };
}

改造完成后,setState仅能接受描述符中定义的状态键,输入其他字符串会直接触发TypeScript类型错误,完全符合需求。

完整可运行示例代码:

// 补充MessageObj基础类型定义
type MessageObj = {
    reply: (content: string) => void;
};

type State<S extends string> = {
    onMessage: (
        requester: MessageObj,
        stateMachineInstance: StateMachineInstance<S>
    ) => any;
};

type StateMachineDescriptor<S extends string> = {
    initialState: S;
    states: Record<S, State<S>>;
};

type StateMachineInstance<S extends string> = StateMachineDescriptor<S> & {
    currentState: S;
    setState: (newState: S) => void;
    reset: () => void;
};

function createStateMachine<S extends string>(descriptor: StateMachineDescriptor<S>): StateMachineInstance<S> {
    return {
        ...descriptor,
        currentState: descriptor.initialState,
        setState(newState) {
            this.currentState = newState;
        },
        reset() {
            this.currentState = descriptor.initialState;
        }
    };
}

// 使用示例
const myStateMachine = createStateMachine({
    initialState: "state1",
    states: {
        state1: {
            onMessage: (requester, stateMachine) => {
                requester.reply("hello1");
                stateMachine.setState("state2"); // 合法
                // stateMachine.setState("state3"); // 触发TypeScript错误:"state3"不在状态键集合中
            }
        },
        state2: {
            onMessage: (requester, stateMachine) => {
                requester.reply("hello2");
                stateMachine.setState("state1"); // 合法
            }
        }
    }
});

内容的提问来源于stack exchange,提问作者Tramonta

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 00:55:11