简体   繁体   中英

How can I avoid a Typescript Error, TS2345, in the Microsoft Bot Framework's StatePropertyAccessor when I assign a property

While building a bot in Typescript I am getting an error TS2345 error with Typescript version 3.7.2. The error prevents me from creating properties on the fly, even if they are undefined, or even referring to them in the stateProperty accessor.

In the javascript example this is accomplished with the following code without error.

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) {

However, in Typescript I can't figure out a way to avoid the error. I can use the state property directly and attach the property that way but I am not sure that is correct and or when exactly it is attaching to the object and or referring to the DB directly. In this case the DB in memory. In effect it works but again, I am not sure I am on the correct object that would be the one referring to my state property accessor property ie const CONVERSATION_DATA_PROPERTY = 'conversationData';

With that said, when I access the userState directly which is Typed to BotState it does seem to persist through the turn context.

Another question, Is what type should I apply to the user state stateProperty accessor?

I have it set to UserState but I am not sure that is correct. What should the userstate type be set to?

Here is the code example:

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

****Update per changes below

I've added the changes as such based on the information from the answer below.

For the user profile and for conversation data I now add in the index.ts file 2 property accessors.

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

below the state storage implementations I add in the property setters.

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

I added in the dialog data property|DialogData separate from the Dialog State property because I need to access the properties separate from the dialogstate which contains the dialogstack of the conversation state.

Also, it allows me to have a typed dialog StatePropertyAccessor which the dialogstate doesn't allow for.

您是否在抛出错误的行上方的行中尝试了此代码?

//@ts-ignore

I would absolutely avoid accessing UserState or DialgoState directly using something like this.userState.xyz = 'myNewData' . I've seen this cause many, many issues and is why we use the accessors .

Your code example at the end is okay for DialogState but not for UserState . It's kind of a long answer why, but here it goes...

In index.ts , you create ConversationState and UserState . Those are classes in the BotFramework SDK that handle very specific tasks.

  • ConversationState isolates different conversations from each other in storage.
  • UserState isolates different users' data from each other in storage
  • They both extend BotState , which handles how those pieces of storage are actually stored and retrieved.
  • You should never directly manipulate anything on these because the Bot Framework depends on the properties of each of these.

So...the reason that your code example is "wrong" is because you have:

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

...which tells the bot to create an additional UserState object within the existing UserState object. That "works", but since UserState doesn't actually have any properties, TypeScript has no idea what keys and values you want to store in there.

In TypeScript, you're probably seeing errors when using something like this:

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

because you haven't defined what type those objects are supposed to be. You'd need something like

export interface UserProfile {
    name: string;
    data: {
        age: number;
        location: string;
    }
}

[...]
this.userState.createProperty<UserProfile>('UserProfile');
const userProfile: UserProfile = await this.userProfileAccessor.get(turnContext, {});

...or something similar.

Note: You should also make sure that you keep names consistent. For example, if you're using createProperty('UserProfile') , you should name the variable userProfile when retrieving it. Also note that the 'UserProfile`` string just tells createProperty to create an object in UserState with the key name of "UserProfile", so the object would look something like: UserState: { ...UserProfile: {} }`


I'm relatively sure this both addresses all of your issues and provides a fix for them. If not, add some code to your question and I'll provide additional help.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM