Edit: Never mind! I was responding with a solution to a similar (but quite different) problem I was experiencing.

A workaround is for the content script to call repeatedly postMessage and await the result (because postMessage returns a Promise). The plugin's entrypoint script can then resolve that Promise when it wants to send a message to the content script.

Example

(Taken from the custom CodeMirror .vimrc plugin and modified)

Type definitions
// Type definitions

interface FooMessage {
	kind: 'foo';
}

interface BarMessage {
	kind: 'bar';
	content: string;
}

interface SetReceiveMessageCallback {
	kind: 'set-callback';
}

type ToContentScriptMessage = FooMessage|BarMessage;
type FromContentScriptMessage = FooMessage|SetReceiveMessageCallback;
// Content script:

type PostMessageCallback = (message: FromContentScriptMessage)=>Promise<string|ToContentScriptMessage>;
type OnMessageCallback = (message: ToContentScriptMessage)=>void;

const setupOnMessageCallback = async (
	onMessage: OnMessageCallback, postMessage: PostMessageCallback
) => {
	// Handle messages from index.ts in a loop:
	while (true) {
		const callbackResult = await postMessage({
			kind: 'set-callback',
		});

		// Result should be a ToContentScriptMessage
		if (typeof callbackResult === 'string') {
			throw new Error(`Invalid callback result: ${callbackResult}`);
		}

		onMessage(callbackResult);
	}
};

export default (context: { contentScriptId: string, postMessage: PostMessageCallback }) => {
	return {
		plugin: () => {
			setupOnMessageCallback(message => {
				console.log('Message from index.ts: ', message);
			}, context.postMessage);
		}
	};
};
// index.ts
joplin.plugins.register({
	onStart: async () => {
		const contentScriptId = `some-content-script-id-here`;
		let messageContentScriptCallback: MessageContentScriptCallback|null = null;
		await joplin.contentScripts.onMessage(contentScriptId, (message: FromContentScriptMessage) => {
			if (message.kind === 'set-callback') {
				return new Promise(resolve => {
					// Store resolve as a callback — we can use it to communicate with the contentScript.
					messageContentScriptCallback = resolve;
				});
			}

			// Handle other message types here.
		});
		await joplin.contentScripts.register(
			ContentScriptType.CodeMirrorPlugin,
			contentScriptId,
			'path/to/content-script.js',
		);
		
		...

		// Send a message to the content script
		messageContentScriptCallback({
			kind: 'foo'
		});
	}
});