rugk: > Argument of type 'string' is not assignable to parameter of type '{ [x: string]: string; }'.ts(2345)
for rowserCommunication.addListener
Now the issue is wrong JSDOC actually.
See #file:BrowserCommunication.js * @param {COMMUNICATION_MESSAGE_TYPE} messageType type of message is wrong JSDOC.
If you see #file:BrowserCommunicationTypes.js you see it is an object of strings, but i should just be used more or less like an enum (which JS itself does not have), so you provide a specific value, but cannot provide any arbotrary string.
How can I fix the JSDoc to represent that?
GitHub Copilot: You are correct: COMMUNICATION_MESSAGE_TYPE is an object (used as an enum), so the JSDoc type for parameters expecting a value from it should not be COMMUNICATION_MESSAGE_TYPE (the object), but rather a value from it.
To represent this in JSDoc, you can use:
keyof typeof COMMUNICATION_MESSAGE_TYPE(TypeScript only)- Or, for plain JSDoc, you can use a union of string literals, but that's verbose.
- The most common and readable way in JSDoc is to use
stringand add a comment, or use@enumto define the possible values.
Best practice for JSDoc in this case: Define a typedef for the possible values:
/**
* @typedef {"omnibarToggle"|"autocorrectBackground"|"autocorrectContent"|"contextMenu"|"insert"} CommunicationMessageType
*/
/**
* An object of all available communication types.
*
* @public
* @const
* @type {Object.<string, string>}
*/
export const COMMUNICATION_MESSAGE_TYPE = Object.freeze({
OMNIBAR_TOGGLE: "omnibarToggle",
AUTOCORRECT_BACKGROUND: "autocorrectBackground",
AUTOCORRECT_CONTENT: "autocorrectContent",
CONTEXT_MENU: "contextMenu",
INSERT: "insert"
});Then, in your function JSDoc, use:
/**
* Add a listener for a specific type.
*
* @public
* @param {CommunicationMessageType} messageType type of message to receive
* @param {listenerCallback} callback
* @returns {void}
*/
export function addListener(messageType, callback) {
// ...existing code...
}Summary:
- Define a
@typedeffor the allowed string values. - Use that typedef in your function JSDoc.
This will make your types clear and help with editor/type checking support.
Similar code found with 1 license type
rugk: A better solution than re-defining all values again with COMMUNICATION_MESSAGE_TYPE?
keyof typeof COMMUNICATION_MESSAGE_TYPE looks fine at first (in the method signature rendering by VSCOde), but at least in VSCode it does not enforce the type here. I can also enter a string and it does not complain.
See also #file:jsconfig.json
GitHub Copilot: You're correct:
COMMUNICATION_MESSAGE_TYPEis an object, not a TypeScript enum.keyof typeof COMMUNICATION_MESSAGE_TYPEgives you the keys ("OMNIBAR_TOGGLE", etc.), not the values ("omnibarToggle", etc.).- But your API expects the values (e.g.,
"omnibarToggle"), not the keys.
Because in plain JS with JSDoc, VSCode's type inference is limited.
Even with @param {keyof typeof COMMUNICATION_MESSAGE_TYPE} or similar, it can't fully enforce value types for object values, only for keys.
There is no way in JSDoc to automatically infer the union of all values of an object.
You must either:
- Manually define a typedef (as shown before), or
- Use TypeScript, which can infer value types with
typeof COMMUNICATION_MESSAGE_TYPE[keyof typeof COMMUNICATION_MESSAGE_TYPE].
Manual typedef is the only robust way:
/**
* @typedef {"omnibarToggle"|"autocorrectBackground"|"autocorrectContent"|"contextMenu"|"insert"} CommunicationMessageType
*/
export const COMMUNICATION_MESSAGE_TYPE = Object.freeze({
OMNIBAR_TOGGLE: "omnibarToggle",
AUTOCORRECT_BACKGROUND: "autocorrectBackground",
AUTOCORRECT_CONTENT: "autocorrectContent",
CONTEXT_MENU: "contextMenu",
INSERT: "insert"
});And use it:
/**
* @param {CommunicationMessageType} messageType
*/
export function addListener(messageType, callback) { ... }- There is no way to avoid re-defining the values in JSDoc.
- TypeScript can infer value types, but JSDoc cannot.
- Manual typedef is the only way for value enforcement in JS+JSDoc.
If you want true enforcement, migrate to TypeScript.
Otherwise, manual typedef is the best you can do in JS.