Since the last update, when importing a messageChannel in LWC, the import is being recognized as a String instead of a MessageChannel

Issue #2099 resolved
Darrion created an issue

Steps to reproduce:

Create an LWC

Create a messageChannel by navigating to force-app\main\default\messageChannels and creating a new message channel MC.messageChannel-meta.xml

Replace the contents with the below:

<LightningMessageChannel xmlns="http://soap.sforce.com/2006/04/metadata">
 <masterLabel>MC</masterLabel> 
 <isExposed>true</isExposed> 
 <description>This is a sample Lightning Message Channel.</description> 
 </LightningMessageChannel>

In your LWC, add the following import

import MC from '@salesforce/messageChannel/MC__c';

Create a function with parameter and add a parameter hint that it is of type MessageChannel:

/** 
* @param {MessageChannel} messageChannel 
*/ 
testMC(messageChannel){console.log(messageChannel);}

Call the function with your imported channel:

connectedCallback() { this.testMC(MC); }

MC is now highlighted with message:

‘Argument type string is not assignable to parameter type MessageChannel’.

Comments (14)

  1. Scott Wells repo owner

    Thanks for reporting. I have a whole series of follow-on changes for type safety for this coming week's build. I'll make sure that this gets fixed if it's not already.

  2. Scott Wells repo owner

    So I have a potentially dumb question. What type should imported message channels be? Looking at the docs:

    https://developer.salesforce.com/docs/component-library/documentation/en/lwc/lwc.use_message_channel_intro https://developer.salesforce.com/docs/component-library/bundle/lightning-message-service/documentation

    and the signatures of the functions that take them as parameters, e.g., lightning/messageservice.subscribe and lightning/messageservice.publish, it looks like they're just object. Is that correct, or is there some more specific type with known fields?

    I just want to make sure I get this as close to right as possible in my ongoing quest for more strongly-typed JS/ES6/TS Salesforce dev. Thanks!

  3. Darrion reporter

    Hi Scott 🙂

    Thanks a good question .. So I did a little bit of investigation.

    I console logged the message channel import as-is, and as it turns out, it is in fact a string! However I’ve never seen this error prior to the last update so I did some more digging.

    Turns out, I’ve been type hinting this message channel parameter as MessageChannel, which I assumed was similar to the other type interfaces that IC has such as MessageContext which is a salesforce interface .. but turns out it was referencing the native JS MessageChannel. So technically my type hint was wrong, and when I changed the type hint to Object, the error has disappeared. I guess the last update made IC more type aware and thats why I never saw this error before?

    I do find this a bit weird though, considering that the IDE knows that it is a string but does not complain when the type hint is Object, but did complain when the type hint was MessageChannel. I’m not sure if that in itself is a bug?

    But either way it got me thinking, shouldn’t the Lightning MessageChannel metadata be uniquely identified, much like when you import SObject schema metadata / apex controller metadata in LWC? If this is possible I think it would be a great addition, that way we could type hint a parameter as a Lightning MessageChannel, and I imagine the lightning/messageservice.subscribe and lightning/messageservice.publish methods should still be okay, since it only wants type Object anyway?

    Please let me know your thoughts.

  4. Scott Wells repo owner

    Hey. Yeah, I'm in the process of making that entire namespace strongly-typed even if it's all via marker interfaces, e.g.:

        export function publish(messageContext: MessageContextType, messageChannel: MessageChannel, message?: Object, publisherOptions?: Object): void;
        export function subscribe(messageContext: MessageContextType, messageChannel: MessageChannel, listener: Function, subscriberOptions?: SubscriberOptions | Object): MessageChannelSubscription;
        export function unsubscribe(subscription: MessageChannelSubscription): void;
        export function createMessageContext(): MessageContextType;
        export function releaseMessageContext(messageContext: MessageContextType): void;
    

    Note that SubscriberOptions actually does include a scope field of an enum type, and APPLICATION_SCOPE is now also of that same type thereby tying that all together nicely.

    I'm going to verify that it all looks good across all of the open source projects with significant LWC and tune accordingly, but that should provide much better type checking in the IDE during development.

  5. Darrion reporter

    Awesome 🙂 I assume that this MessageChannel will be a seperate salesforce type and won’t butt heads with the native JS MessageChannel type when we are type hinting?

    Anyways thanks for the quick response 🙂

  6. Scott Wells repo owner

    Yes, it's technically lightning/messageService.MessageChannel, though I just renamed it to MessageChannelType to avoid any chance of ambiguity just as I did with MessageContextType given the constant named MessageContext in the same namespace. A bit of tuning, but hopefully it'll be a good result. The only risk is that someone tries to reference these types in their LWC source code because they see the editor presenting them. I'll chew on how I might mitigate that risk, perhaps via a code inspection that flags direct code references as errors.

  7. Scott Wells repo owner

    Delivered in 2.2.2.0:

    Made the lightning/messageService module much more strongly-typed using synthetic types to help enforce type agreement.

  8. Log in to comment