【问题标题】:How can I avoid a Typescript Error, TS2345, in the Microsoft Bot Framework's StatePropertyAccessor when I assign a property分配属性时,如何避免 Microsoft Bot Framework State PropertyAccessor 中出现 Typescript 错误 TS2345
【发布时间】:2019-11-25 14:57:08
【问题描述】:

在 Typescript 中构建机器人时,Typescript 版本 3.7.2 出现错误 TS2345 错误。该错误使我无法动态创建属性,即使它们未定义,甚至在 stateProperty 访问器中引用它们。

javascript example 中,这是通过以下代码完成的,没有错误。

this.conversationDataAccessor = conversationState.createProperty(CONVERSATION_DATA_PROPERTY);
        this.userProfileAccessor = userState.createProperty(USER_PROFILE_PROPERTY);

        // The state management objects for the conversation and user state.
        this.conversationState = conversationState;
        this.userState = userState;

        this.onMessage(async (turnContext, next) => {
            // Get the state properties from the turn context.
            const userProfile = await this.userProfileAccessor.get(turnContext, {});
            const conversationData = await this.conversationDataAccessor.get(
                turnContext, { promptedForUserName: false });

            if (!userProfile.name) {

但是,在 Typescript 中,我无法找到避免错误的方法。我可以直接使用 state 属性并以这种方式附加属性,但我不确定这是正确的,或者它何时确切地附加到对象或直接引用 DB。在这种情况下,内存中的数据库。实际上它是有效的,但我不确定我是否在正确的对象上,即引用我的状态属性访问器属性的对象,即const CONVERSATION_DATA_PROPERTY = 'conversationData';

话虽如此,当我直接访问键入为BotState 的 userState 时,它​​似乎确实会在转弯上下文中持续存在。

另一个问题,我应该对用户状态 stateProperty 访问器应用什么类型?

我已将其设置为 UserState,但我不确定这是否正确。用户状态类型应该设置为什么?

下面是代码示例:

this.dialogState = this.conversationState.createProperty<DialogState>('DialogState');
this.userProfileAccessor = this.userState.createProperty<UserState>('UserState');

****根据以下更改更新

我已根据以下答案中的信息添加了更改。

对于用户配置文件和对话数据,我现在在 index.ts 文件中添加 2 个属性访问器。

let userProfileAccessor: StatePropertyAccessor<UserProfile>;
let dialogDataAccessor: StatePropertyAccessor<DialogData>;

在我在属性设置器中添加的状态存储实现下方。

dialogDataAccessor = conversationState.createProperty<DialogData>(DIALOG_DATA_PROPERTY);
userProfileAccessor = userState.createProperty<UserProfile>(USER_PROFILE_PROPERTY);

我在对话框数据属性中添加了与对话框状态属性分开的对话框数据,因为我需要访问与包含对话状态的对话框堆栈的对话框状态分开的属性。

另外,它允许我有一个对话框状态不允许的类型化对话框StatePropertyAccessor

【问题讨论】:

    标签: javascript typescript botframework state


    【解决方案1】:

    我绝对会避免使用类似this.userState.x.y.z = 'myNewData' 的方式直接访问UserStateDialgoState。我已经看到这会导致很多很多问题,这也是我们使用 accessors 的原因。

    您最后的代码示例适用于DialogState,但不适用于UserState。这是一个很长的答案为什么,但在这里......

    index.ts,你create ConversationState and UserState。这些是 BotFramework SDK 中处理非常具体的任务的类。

    • ConversationState 在存储中将不同的对话相互隔离。
    • UserState 在存储中将不同用户的数据相互隔离
    • 它们都扩展了BotState,后者处理这些存储片段的实际存储和检索方式。
    • 您永远不应该直接在这些上操作任何东西,因为 Bot Framework 依赖于每一个的属性。

    所以...您的代码示例“错误”的原因是因为您有:

    this.userState.createProperty<UserState>('UserState');
    

    ...告诉机器人在现有的UserState 对象中创建一个额外的UserState 对象。这“有效”,但由于 UserState 实际上没有任何属性,TypeScript 不知道您要在其中存储哪些键和值。

    在 TypeScript 中,您可能会在使用以下内容时看到错误:

    const userProfile = await this.userProfileAccessor.get(turnContext, {});
    const conversationData = await this.conversationDataAccessor.get(
                    turnContext, { promptedForUserName: false });
    

    因为您还没有定义这些对象应该是什么类型。你需要类似的东西

    export interface UserProfile {
        name: string;
        data: {
            age: number;
            location: string;
        }
    }
    
    [...]
    this.userState.createProperty<UserProfile>('UserProfile');
    const userProfile: UserProfile = await this.userProfileAccessor.get(turnContext, {});
    

    ...或类似的东西。

    注意:您还应确保名称保持一致。例如,如果您使用createProperty('UserProfile'),则在检索变量时应将其命名为userProfile。还要注意'UserProfile`` string just tellscreatePropertyto create an object inUserStatewith the key name of "UserProfile", so the object would look something like:UserState: { ...UserProfile: {} }`


    我比较确定这既能解决您的所有问题,又能解决这些问题。如果没有,请在您的问题中添加一些代码,我会提供其他帮助。

    【讨论】:

    • 谢谢。我发现我将在我的问题中更新的另一件事,你可以回答会很棒。问题是这样的。当从另一个对话框访问访问器时,让我们说瀑布,我想使用将输入到 StatePropertyAccessor 的 userProfileAccessor,正如您之前所说,我现在是否可以访问状态属性访问器而无需获得get 未定义错误?除非我在构造函数中重用 this.userProfileAccessor = this.userState.createProperty... 属性,否则会发生错误?
    • 所以是的,错误是一样的。让我准确解释一下我在做什么,如果是这样,你可以告诉我。似乎我需要在我想通过 stateproperty 访问器使用和或编辑属性的每个构造函数中设置 creatproperty。是这样吗:这是一个例子:this.userProfileAccessor = this.userState.createProperty&lt;UserProfile&gt;('ProfileState');
    • @ChristianMatthew 啊。我明白你的意思了。这可以通过在更多根对话框中声明您的userProfileAccessor 来解决,然后将其传递给每个对话框的构造函数——您需要将构造函数从constructor(conversationState, userState) 之类的东西编辑为constructor(userProfileAccessor) 之类的东西跨度>
    • 我就是这么想的……让我想想那个,看看我想出了什么。但对话状态也必须这样做
    • 所以任何低于根目录但仍然是对话框的东西,即 dialogbot 或 welcomedialogbot 我仍然需要按照我的描述建立 statepropertyacessor?如果这有意义
    【解决方案2】:

    您是否在引发错误的行上方尝试了此代码?

    //@ts-ignore
    

    【讨论】:

    • 谢谢你的作品。还有我,想知道为什么它不起作用
    猜你喜欢
    • 2017-05-27
    • 2019-12-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-14
    相关资源
    最近更新 更多