npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@kjn/electron-typesafe-ipc

v2.0.0

Published

TypeSafe IPC functions of Electron with TypeScript.

Downloads

381

Readme

@kjn/electron-typesafe-ipc

semantic-release: angular

This package contains a library that includes type safe versions of the existing electron IPC methods.

Note: Since this is a library, the functionality is opt-in and doesn't change the behaviour in any form. Rather this library focusses on SOLELY adding TypeScript support to the existing electron IPC methods.

Regular Electron IPC (unsafe)

// Type of r is Promise<any>
const r = await ipcRenderer.invoke("substract", 1, 1);

// No warning. Potential cause for run-time errors
const r = await ipcRenderer.invoke("substract", 1, "hello");

With @kjn/electron-typesafe-ipc (safe, better)

The user can explicitly state the types of both the parameters and the return type.

// Type of r is Promise<number>
const r = await invoke<[number, number], number>("substract", 1, 1);

// Displays an error because "hello" isn't a number
const r = await invoke<[number, number], number>("substract", 1, "hello");

With Dedicated IpcChannels (safe, clean, BEST)

Link the handler function to the invoke method by adding structure to the channels. This requires users to use a predefined and specific structure to keep their channels and handlers in.

Dedicated IpcChannel will however improve the Separation of Concern and it complies with the Single Responsibility Principle. Therefore in terms of Architecture its often the right choice.

// [Can be defined anywhere] Should implement the IpcChannel interface
const substractIpcChannel = {
  name: "SUBSTRACT_CHANNEL",
  handler: (ev: IpcMainInvokeEvent, n1: number, n2: number): number => n1 - n2,
};

// [@main.ts] this will add the handler to the 'SUBSTRACT_CHANNEL` as defined in the object.
registerIpcChannel(substractIpcChannel);

// [@preload.ts]  this will call the substractIpcChannel handler with the parameters 10 and 5
//  additionally both the return type and the parameters are strongly typed.
const r = invokeIpcChannel(substractIpcChannel, 10, 5); // == Promise<number>

Table of content

Usage

Installation

Install the package with npm or yarn (or just copy the files whatever works)

npm install --save-dev @kjn/electron-typesafe-ipc

yarn add -D @kjn/electron-typesafe-ipc

Import the desired method where relevant

import { invoke, handle, invokeIpcChannel, registerIpcChannel } from "@kjn/electron-typesafe-ipc";

// For more details on the API interface check the docs below

Use the typesafe methods according to your needs.

Recommended Usage

Use the invokeIpcChannel and registerIpcChannel methods instead of the original invoke and handle calls. This will work the best for large scale projects and forces you to adapt to good architecture practices.

import { IpcChannel } from "@kjn/electron-typesafe-ipc";

const substractIpcChannel: IpcChannel<[number, number], number> = {
  name: "SUBSTRACT_CHANNEL",
  handler: (ev, n1: number, n2: number) => n1 + n2,
};

// register a ipcChannel handler
registerIpcChannel(substractIpcChannel);

// invoke the handler of the ipcChannel AND benefit from the typehints that it provides
const r = await invokeIpcChannel(substractIpcChannel, 10, 4);

Alternative Usage

The invoke and handle calls are cross compatible replacements for the ipcRenderer.invoke and ipcMain.handle calls respectively. Therefore they can be swapped in and out without any implications to the logic of the code.

type SubstractParamsType = [number, number];
type SubstractReturnType = number;

// e.g. add a handler, the generics force the handler to accept 2 numbers as input and return a number as output
handle<SubstractParamsType, SubstractReturnType>("substract", (ev, n1, n2) => n1 + n2);

// e.g. invoke a handler AND benefit from the typehints that it provides
const result = invoke<SubstractParamsType, SubstractReturnType>("substract", 10, 30);

The first generic in the handle and invoke calls represents the parameters of the handler as an array. The second generic represents the return type.

API

Handle

import { handle } from "@kjn/electron-typesafe-ipc";

The handle function contains 2 generics that can be passed to it: P and R to represent the parameters and return type of the handler function respectively.

handle<P, R>(<channelName>, <handlerFunction>)

Handle P Generic

P (generic handle<P, _>), indicates the array of the parameter types of the handler, a few examples:

// TypeHint to use: 2 numbers as paremeters for the handler
handle<[number, number]>("SUBSTRACT_CHANNEL", (ev, n1, n2) => n1 + n2);

// TypeHint to use: no parameters for the handler
const trueChannelHandler = (ev) => !!ev;
handle<[]>("TRUE_CHANNEL", trueChannelHandler);

// TypeHint to use: a string, number and boolean as parameters for the handler
function randomChannelHandler(ev, str, num, bool) {
  if (str === "hello" || num < 1 || bool === true) {
    throw Error("Error");
  }
}
handle<[string, number, boolean]>("RANDOM_CHANNEL", (ev, str, num, bool) =>
  randomChannelHandler(ev, str, num + 2, bool)
);

Note: P doesn't include the first (and always present) IpcMainInvokeEvent parameter

Handle R Generic

R (generic handle<_, R>), indicates the return type of the handler function, a few examples:

// Expect a number as the return type of the handler
handle<[], number>("SUBSTRACT_CHANNEL", (ev, n1: number, n2: number) => n1 + n2);

// Expect null as the return type of the handler
handle<[], null>("LOG_CHANNEL", (ev) => {
  console.log("log");
  return null;
});

// Expect a boolean OR string as the return type of the handler
handle<[num], boolean | string>("IS_PIE_CHANNEL", (ev, n1) => {
  if (n1 === 314) {
    return "pie?";
  }
  return n1 > 100;
});

Invoke

import { invoke } from "@kjn/electron-typesafe-ipc";

The invoke function contains 2 generics that can be passed to it: P and R, which represent the parameters type and return type of the handler call respectively.

invoke<P, R>(<channelName>, <param1: P[0]>, <param2: P[1]>, ..., <paramX: P[X]>): R

Invoke P Generic

P (generic invoke<P, _>), indicates the array of the parameter types, a few examples:

// Indicates that there are 2 parameters, both numbers
const r1 = invoke<[number, number]>("SUBSTRACT_CHANNEL", 100, 10); // == Promise<any>

// Indicates that there are no parameters
const r2 = invoke<[]>("TRUE_CHANNEL"); // == Promise<any>

// Indicates that there is a string, number and boolean as parameters
const r3 = invoke<[string, number, boolean]>("RANDOM_CHANNEL", "Hello world", 10, false); // == Promise<any>

Invoke R Generic

R (generic invoke<_, R>), indicates the return type, a few examples:

// Indicates that the return type is number
const r1 = invoke<[number, number], number>("SUBSTRACT_CHANNEL", 100, 10); // == Promise<number>

// Indicates that the return type is null
const r2 = invoke<[], null>("LOG_CHANNEL"); // Promise<null>

// Indicates that the return type is either boolean OR string
const r3 = invoke<[string], boolean | string>("RANDOM_CHANNEL", "str as input"); // Promise<boolean | string>

Note: since invoke is a asynchronous call, the return types are wrapped in Promises

registerIpcChannel

import { registerIpcChannel } from "@kjn/electron-typesafe-ipc";

Add a handler for an ipc channel, requires an object that implements the IpcChannel interface. Typechecking will be handled automatically.

import { IpcChannel } from "@kjn/electron-typesafe-ipc";

const substractIpcChannel: IpcChannel<[number, number], number> = {
  name: "SUBSTRACT_CHANNEL",
  handler: (ev, n1: number, n2: number) => n1 - n2,
};

registerIpcChannel(substractIpcChannel);

InvokeIpcChannel

import { invokeIpcChannel } from "@kjn/electron-typesafe-ipc";

Invoke the handler of an ipc channel, requires an object that implements the IpcChannel interface. Typechecking will be handled automatically.

Also relies on the handler existing for that ipcChannel.

import { IpcChannel } from "@kjn/electron-typesafe-ipc";

const substractIpcChannel: IpcChannel<[number, number], number> = {
  name: "SUBSTRACT_CHANNEL",
  handler: (ev, n1: number, n2: number) => n1 - n2,
};

const result = await invokeIpcChannel(substractIpcChannel, 10, 100);

IpcChannel Interface

The IpcChannel interface defines the simplest blueprint to which an object should adhere to be used with the registerIpcChannel and invokeIpcChannel calls.

The IpcChannel interface contains 2 generics that can be passed to it: P and R to represent the parameters and return type of the handler respectively.

IpcChannel<P, R>

IpcChannel P Generic

P (generic IpcChannel<P, _>), indicates the array of the parameter types of the handler, a few examples:

// 2 numbers as parameters for the handler
const substractIpcChannel: IpcChannel<[number, number]> = {
  name: "SUBSTRACT_CHANNEL",
  handler: (ev, n1, n2) => n1 - n2, // TypeScript will treath n1 and n2 as numbers
};

// no parameters for the handler
const printLogIpcChannel: IpcChannel<[]> = {
  name: "PRINT_LOG_CHANNEL",
  handler: (ev) => {
    console.log("log");
  },
};

// a number and boolean as parameters for the handler
const ageCheckIpcChannel: IpcChannel<[number, boolean]> = {
  name: "AGE_CHECK_CHANNEL",
  handler: (ev, age, adultRequired) => {
    if (age < 18 && adultRequired) {
      return false;
    }
    return true;
  },
};

IpcChannel R Generic

R (generic IpcChannel<_, R>), indicates the return type of the handler, a few examples:

// number as a return type for the handler
const getMsIpcChannel: IpcChannel<[], number> = {
  name: "GET_MS_CHANNEL",
  handler: (ev) => {
    return new Date().getMilliseconds();
  },
};

// CustomType as return type for the handler
const customTypeIpcChannel: IpcChannel<[], CustomType> = {
  name: "CUSTOM_TYPE_CHANNEL",
  handler: (ev) => {
    return { x: 1, y: 92 } as CustomType;
  },
};
type CustomType = {
  x: number;
  y: number;
};