title: contextBridge.exposeInMainWorld and IPC with Typescript in Electron app: Cannot read property 'send' of undefined
body: <p>I defined contextBridge ( <a href="https://www.electronjs.org/docs/all#contextbridge" rel="noreferrer">https://www.electronjs.org/docs/all#contextbridge</a> )
  in preload.js as follows:</p>
  <pre><code>const {
    contextBridge,
    ipcRenderer
  } = require(&quot;electron&quot;)
  
  contextBridge.exposeInMainWorld(
    &quot;api&quot;, {
        send: (channel, data) =&gt; {
            ipcRenderer.invoke(channel, data).catch(e =&gt; console.log(e))
        },
        receive: (channel, func) =&gt; {
          console.log(&quot;preload-receive called. args: &quot;);
          ipcRenderer.on(channel, (event, ...args) =&gt; func(...args));
        },
        // https://www.electronjs.org/docs/all#ipcrenderersendtowebcontentsid-channel-args
        electronIpcSendTo: (window_id: string, channel: string, ...arg: any) =&gt; {
          ipcRenderer.sendTo(window_id, channel, arg);
        },
        // https://github.com/frederiksen/angular-electron-boilerplate/blob/master/src/preload
  /preload.ts
        electronIpcSend: (channel: string, ...arg: any) =&gt; {
          ipcRenderer.send(channel, arg);
        },
        electronIpcSendSync: (channel: string, ...arg: any) =&gt; {
          return ipcRenderer.sendSync(channel, arg);
        },
        electronIpcOn: (channel: string, listener: (event: any, ...arg: any) =&gt; void) =&gt; {
          ipcRenderer.on(channel, listener);
        },
        electronIpcOnce: (channel: string, listener: (event: any, ...arg: any) =&gt; void) =&gt; {
          ipcRenderer.once(channel, listener);
        },
        electronIpcRemoveListener:  (channel: string, listener: (event: any, ...arg: any) =&gt; 
  void) =&gt; {
          ipcRenderer.removeListener(channel, listener);
        },
        electronIpcRemoveAllListeners: (channel: string) =&gt; {
          ipcRenderer.removeAllListeners(channel);
        }
    }
  )
  </code></pre>
  <p>I defined a global.ts :</p>
  <pre><code>export {}
  declare global {
    interface Window {
      &quot;api&quot;: {
        send: (channel: string, ...arg: any) =&gt; void;
        receive: (channel: string, func: (event: any, ...arg: any) =&gt; void) =&gt; void;
        // https://github.com/frederiksen/angular-electron-boilerplate/blob/master/src/preload
  /preload.ts
        // https://www.electronjs.org/docs/all#ipcrenderersendtowebcontentsid-channel-args
        electronIpcSendTo: (window_id: string, channel: string, ...arg: any) =&gt; void;
        electronIpcSend: (channel: string, ...arg: any) =&gt; void;
        electronIpcOn: (channel: string, listener: (event: any, ...arg: any) =&gt; void) =&gt; void;
        electronIpcSendSync: (channel: string, ...arg: any) =&gt; void;
        electronIpcOnce: (channel: string, listener: (event: any, ...arg: any) =&gt; void) =&gt; 
  void;
        electronIpcRemoveListener:  (channel: string, listener: (event: any, ...arg: any) =&gt;
   void) =&gt; void;
        electronIpcRemoveAllListeners: (channel: string) =&gt; void;
      }
    }
  }
  </code></pre>
  <p>and in the renderer process App.tsx I call window.api.send :</p>
  <pre><code>window.api.send('open-type-A-window', ''); 
  </code></pre>
  <p>The typescript compilation looks fine:</p>
  <pre><code>yarn run dev
  yarn run v1.22.5 
  $ yarn run tsc &amp;&amp; rimraf dist &amp;&amp; cross-env NODE_ENV=development webpack --watch --progress 
  --color
  $ tsc
  95% emitting emit(node:18180) [DEP_WEBPACK_COMPILATION_ASSETS] DeprecationWarning:      
  Compilation.assets will be frozen in future, all modifications are deprecated.
  
  BREAKING CHANGE: No more changes should happen to Compilation.assets after sealing the 
  Compilation.
      Do changes to assets earlier, e. g. in Compilation.hooks.processAssets.
      Make sure to select an appropriate stage from Compilation.PROCESS_ASSETS_STAGE_*.
  (Use `node --trace-deprecation ...` to show where the warning was created)
  asset main.bundle.js 32.6 KiB [emitted] (name: main) 1 related asset
  asset package.json 632 bytes [emitted] [from: package.json] [copied]
  cacheable modules 26.2 KiB
    modules by path ./node_modules/electron-squirrel-startup/ 18.7 KiB
      modules by path ./node_modules/electron-squirrel-startup/node_modules/debug/src/*.js 15 
  KiB 4 modules
      ./node_modules/electron-squirrel-startup/index.js 1 KiB [built] [code generated]
      ./node_modules/electron-squirrel-startup/node_modules/ms/index.js 2.7 KiB [built] [code 
  generated]
    ./src/main/main.ts 6.82 KiB [built] [code generated]
    ./node_modules/file-url/index.js 684 bytes [built] [code generated]
  external &quot;path&quot; 42 bytes [built] [code generated]
  external &quot;url&quot; 42 bytes [built] [code generated]
  external &quot;electron&quot; 42 bytes [built] [code generated]
  external &quot;child_process&quot; 42 bytes [built] [code generated]
  external &quot;tty&quot; 42 bytes [built] [code generated]
  external &quot;util&quot; 42 bytes [built] [code generated]
  external &quot;fs&quot; 42 bytes [built] [code generated]
  external &quot;net&quot; 42 bytes [built] [code generated]
  webpack 5.21.2 compiled successfully in 4313 ms
  
  asset renderer.bundle.js 1000 KiB [emitted] (name: main) 1 related asset
  asset index.html 196 bytes [emitted]
  runtime modules 937 bytes 4 modules
  modules by path ./node_modules/ 990 KiB
    modules by path ./node_modules/scheduler/ 31.8 KiB 4 modules
    modules by path ./node_modules/react/ 70.6 KiB 2 modules
    modules by path ./node_modules/react-dom/ 875 KiB 2 modules
    modules by path ./node_modules/css-loader/dist/runtime/*.js 3.78 KiB 2 modules
    ./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js 6.67 KiB [built] 
  [code generated]
    ./node_modules/object-assign/index.js 2.06 KiB [built] [code generated]
  modules by path ./src/ 5 KiB
    modules by path ./src/app/styles/*.less 3.16 KiB
      ./src/app/styles/index.less 385 bytes [built] [code generated]
      ./node_modules/css-loader/dist/cjs.js!./node_modules/less-loader/dist/cjs.js!./src/app
  /styles/index.less 2.78 KiB [built] [code generated]
    ./src/renderer/renderer.tsx 373 bytes [built] [code generated]
    ./src/app/components/App.tsx 1.48 KiB [built] [code generated]
  webpack 5.21.2 compiled successfully in 4039 ms
  </code></pre>
  <p>But I get <code>Cannot read property 'send' of undefined</code></p>
  <p><a href="https://i.stack.imgur.com/3PEHf.png" rel="noreferrer"><img src="https://i.stack.imgur.com/3PEHf.png" alt="enter image description here" /></a></p>
  <p>If I set in App.tsx :</p>
  <pre><code>const sendProxy = window.api.send;
  </code></pre>
  <p>I get the same error and the window is not rendered :</p>
  <p><a href="https://i.stack.imgur.com/svAG0.png" rel="noreferrer"><img src="https://i.stack.imgur.com/svAG0.png" alt="enter image description here" /></a></p>
  <p>What am I doing wrongly with Typescript and with Electron IPC?
  Looking forward to your kind help</p>