在 TypeScript 中创建电子菜单?
Create Electron Menu in TypeScript?
刚刚使用 TypeScript 启动了一个简单的 Electron 应用程序,我正在尝试设置我的自定义菜单。我按照 JS 中的示例进行操作,但是行
menu = Menu.buildFromTemplate(template);
编译失败并出现错误:
main.ts(109,35): error TS2345: Argument of type '({ label: string; submenu: ({ role: string; } | { type: string; })[]; } | { role: string; submenu...' is not assignable to parameter of type 'MenuItemConstructorOptions[]'.
我一定是漏掉了什么。在任何地方都找不到类型“MenuItemConstructorOptions(但我可能找错了地方)。我的 main.ts:
的完整代码
import { app, BrowserWindow, screen, Menu } from 'electron';
import * as path from 'path';
let win, menu;
function createWindow() {
const electronScreen = screen;
const size = electronScreen.getPrimaryDisplay().workAreaSize;
win = new BrowserWindow({
x: 0,
y: 0,
width: size.width,
height: size.height
});
// and load the index.html of the app.
win.loadURL('file://' + __dirname + '/index.html');
win.webContents.openDevTools();
win.on('closed', () => {
win = null;
});
}
function createMenu() {
const template = [{
label: 'Edit',
submenu: [
{ role: 'undo' },
{ role: 'redo' },
{ type: 'separator' },
{ role: 'cut' },
{ role: 'copy' },
{ role: 'paste' },
{ role: 'pasteandmatchstyle' },
{ role: 'delete' },
{ role: 'selectall' }
]
},
{
label: 'View',
submenu: [
{ role: 'reload' },
{ role: 'forcereload' },
{ role: 'toggledevtools' },
{ type: 'separator' },
{ role: 'resetzoom' },
{ role: 'zoomin' },
{ role: 'zoomout' },
{ type: 'separator' },
{ role: 'togglefullscreen' }
]
},
{ role: 'window', submenu: [{ role: 'minimize' }, { role: 'close' }] },
{
role: 'help',
submenu: [{
label: 'Learn More',
click() { require('electron').shell.openExternal('https://electron.atom.io');
}
}]
}
];
menu = Menu.buildFromTemplate(template);
Menu.setApplicationMenu(menu);
}
try {
app.on('ready', function() {
createWindow();
createMenu();
});
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
app.on('activate', () => {
if (win === null) {
createWindow();
}
});
} catch (e) {
throw e;
}
我猜你有一个错误/打字错误:
{ type: 'separator' },
TypeScript 无法解析类型,因为未知 type
属性(根据您的其他输入应该是 role
)
我无法在 TS 中获取适用于 JS 的示例。 MenuItemConstructorOptions
是电子包中 electron.d.ts
文件中定义的接口。但是,我通过单独定义菜单条目并将它们推送到空数组找到了解决方法。有趣的是,里面的子菜单条目被接受并且没有问题地工作。这是有效的代码:
function createMenu() {
const template = [];
// Edit Menu
template.push({
label: 'Edit',
submenu: [
{ role: 'undo' },
{ role: 'redo' },
{ type: 'separator' },
{ role: 'cut' },
{ role: 'copy' },
{ role: 'paste' },
{ role: 'pasteandmatchstyle' },
{ role: 'delete' },
{ role: 'selectall' }
]
});
// View Menu
template.push({
label: 'View',
submenu: [
{ role: 'reload' },
{ role: 'forcereload' },
{ role: 'toggledevtools' },
{ type: 'separator' },
{ role: 'resetzoom' },
{ role: 'zoomin' },
{ role: 'zoomout' },
{ type: 'separator' },
{ role: 'togglefullscreen' }
]
});
// Windown menu
template.push({
role: 'window',
submenu: [{ role: 'minimize' }, { role: 'close' }]
});
// Help menu
template.push({
role: 'help',
submenu: [
{
label: 'Learn More',
click() {
require('electron').shell.openExternal('https://electron.atom.io');
}
}
]
});
if (process.platform === 'darwin') {
template.unshift({
label: app.getName(),
submenu: [
{ role: 'about' },
{ type: 'separator' },
{ role: 'services', submenu: [] },
{ type: 'separator' },
{ role: 'hide' },
{ role: 'hideothers' },
{ role: 'unhide' },
{ type: 'separator' },
{ role: 'quit' }
]
});
// Edit menu
template[1].submenu.push(
{ type: 'separator' },
{ label: 'Speech', submenu: [{ role: 'startspeaking' }, { role: 'stopspeaking' }] }
);
// Window menu
template[3].submenu = [{ role: 'close' }, { role: 'minimize' }, { role: 'zoom' }, { type: 'separator' }, { role: 'front' }];
}
menu = Menu.buildFromTemplate(template);
Menu.setApplicationMenu(menu);
}
如果有人遇到同样的问题,希望这对您有所帮助
对我来说,将模板常量的类型设置为 Electron.MenuItemConstructorOptions[]
就足够了。
例如:
const template: Electron.MenuItemConstructorOptions[] = [{
label: 'Edit',
submenu: [
{ role: 'undo' },
{ role: 'redo' },
{ type: 'separator' },
{ role: 'cut' },
{ role: 'copy' },
{ role: 'paste' },
{ role: 'pasteandmatchstyle' },
{ role: 'delete' },
{ role: 'selectall' }
]
},
{
label: 'View',
submenu: [
{ role: 'reload' },
{ role: 'forcereload' },
{ role: 'toggledevtools' },
{ type: 'separator' },
{ role: 'resetzoom' },
{ role: 'zoomin' },
{ role: 'zoomout' },
{ type: 'separator' },
{ role: 'togglefullscreen' }
]
},
{ role: 'window', submenu: [{ role: 'minimize' }, { role: 'close' }] },
{
role: 'help',
submenu: [{
label: 'Learn More',
click() {
require('electron').shell.openExternal('https://electron.atom.io');
}
}]
}
];
在MenuItemConstructorOptions界面中,子菜单属性定义为联合类型。因此,需要将 属性 强制转换为 MenuItemConstructorOptions 数组,以便识别推送运算符:
(windowMenu.submenu as MenuItemConstructorOptions[]).push(
{
type: 'separator',
},
{
label: 'Bring All To Front',
role: 'front'
}
);
对我来说问题是正确的角色大写:
{ role: 'forceReload' },
{ role: 'toggleDevTools' }
超过
{ role: 'forcereload' },
{ role: 'toggledevtools' }
参见docs。
当我基于 Electron 的菜单语法时,我遇到了同样的错误 Menu
example, which works fine in JavaScript but upsets TypeScript. Unfortunately the MenuItemConstructorOptions[]
cast for template
as 对我不起作用。
在 Electron 的示例中,TypeScript 似乎在三元组上运行,无法确定它们的结果类型。在我的例子中,在包含三元组的右括号后添加 as MenuItemConstructorOptions[]
让 TypeScript 意识到它们毕竟是有效的子菜单。
有效 TypeScript 中的完整 Electron 示例:
import { app, Menu, MenuItemConstructorOptions, shell } from "electron"
const isMac = process.platform === 'darwin'
const menu = Menu.buildFromTemplate(
[
// { role: 'appMenu' }
...(isMac ? [{
label: app.name,
submenu: [
{ role: 'about' },
{ type: 'separator' },
{ role: 'services' },
{ type: 'separator' },
{ role: 'hide' },
{ role: 'hideothers' },
{ role: 'unhide' },
{ type: 'separator' },
{ role: 'quit' }
]
}] : []) as MenuItemConstructorOptions[],
// { role: 'fileMenu' }
{
label: 'File',
submenu: [
isMac ? { role: 'close' } : { role: 'quit' }
] as MenuItemConstructorOptions[]
},
// { role: 'editMenu' }
{
label: 'Edit',
submenu: [
{ role: 'undo' },
{ role: 'redo' },
{ type: 'separator' },
{ role: 'cut' },
{ role: 'copy' },
{ role: 'paste' },
...(isMac ? [
{ role: 'pasteAndMatchStyle' },
{ role: 'delete' },
{ role: 'selectAll' },
{ type: 'separator' },
{
label: 'Speech',
submenu: [
{ role: 'startSpeaking' },
{ role: 'stopSpeaking' }
]
}
] : [
{ role: 'delete' },
{ type: 'separator' },
{ role: 'selectAll' }
]) as MenuItemConstructorOptions[]
]
},
// { role: 'viewMenu' }
{
label: 'View',
submenu: [
{ role: 'reload' },
{ role: 'forceReload' },
{ role: 'toggleDevTools' },
{ type: 'separator' },
{ role: 'resetZoom' },
{ role: 'zoomIn' },
{ role: 'zoomOut' },
{ type: 'separator' },
{ role: 'togglefullscreen' }
]
},
// { role: 'windowMenu' }
{
label: 'Window',
submenu: [
{ role: 'minimize' },
{ role: 'zoom' },
...(isMac ? [
{ type: 'separator' },
{ role: 'front' },
{ type: 'separator' },
{ role: 'window' }
] : [
{ role: 'close' }
]) as MenuItemConstructorOptions[]
]
},
{
role: 'help',
submenu: [
{
label: 'Learn More',
click: async () => {
await shell.openExternal('https://electronjs.org')
}
}
]
}
]
)
Menu.setApplicationMenu(menu)
刚刚使用 TypeScript 启动了一个简单的 Electron 应用程序,我正在尝试设置我的自定义菜单。我按照 JS 中的示例进行操作,但是行
menu = Menu.buildFromTemplate(template);
编译失败并出现错误:
main.ts(109,35): error TS2345: Argument of type '({ label: string; submenu: ({ role: string; } | { type: string; })[]; } | { role: string; submenu...' is not assignable to parameter of type 'MenuItemConstructorOptions[]'.
我一定是漏掉了什么。在任何地方都找不到类型“MenuItemConstructorOptions(但我可能找错了地方)。我的 main.ts:
的完整代码import { app, BrowserWindow, screen, Menu } from 'electron';
import * as path from 'path';
let win, menu;
function createWindow() {
const electronScreen = screen;
const size = electronScreen.getPrimaryDisplay().workAreaSize;
win = new BrowserWindow({
x: 0,
y: 0,
width: size.width,
height: size.height
});
// and load the index.html of the app.
win.loadURL('file://' + __dirname + '/index.html');
win.webContents.openDevTools();
win.on('closed', () => {
win = null;
});
}
function createMenu() {
const template = [{
label: 'Edit',
submenu: [
{ role: 'undo' },
{ role: 'redo' },
{ type: 'separator' },
{ role: 'cut' },
{ role: 'copy' },
{ role: 'paste' },
{ role: 'pasteandmatchstyle' },
{ role: 'delete' },
{ role: 'selectall' }
]
},
{
label: 'View',
submenu: [
{ role: 'reload' },
{ role: 'forcereload' },
{ role: 'toggledevtools' },
{ type: 'separator' },
{ role: 'resetzoom' },
{ role: 'zoomin' },
{ role: 'zoomout' },
{ type: 'separator' },
{ role: 'togglefullscreen' }
]
},
{ role: 'window', submenu: [{ role: 'minimize' }, { role: 'close' }] },
{
role: 'help',
submenu: [{
label: 'Learn More',
click() { require('electron').shell.openExternal('https://electron.atom.io');
}
}]
}
];
menu = Menu.buildFromTemplate(template);
Menu.setApplicationMenu(menu);
}
try {
app.on('ready', function() {
createWindow();
createMenu();
});
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
app.on('activate', () => {
if (win === null) {
createWindow();
}
});
} catch (e) {
throw e;
}
我猜你有一个错误/打字错误:
{ type: 'separator' },
TypeScript 无法解析类型,因为未知 type
属性(根据您的其他输入应该是 role
)
我无法在 TS 中获取适用于 JS 的示例。 MenuItemConstructorOptions
是电子包中 electron.d.ts
文件中定义的接口。但是,我通过单独定义菜单条目并将它们推送到空数组找到了解决方法。有趣的是,里面的子菜单条目被接受并且没有问题地工作。这是有效的代码:
function createMenu() {
const template = [];
// Edit Menu
template.push({
label: 'Edit',
submenu: [
{ role: 'undo' },
{ role: 'redo' },
{ type: 'separator' },
{ role: 'cut' },
{ role: 'copy' },
{ role: 'paste' },
{ role: 'pasteandmatchstyle' },
{ role: 'delete' },
{ role: 'selectall' }
]
});
// View Menu
template.push({
label: 'View',
submenu: [
{ role: 'reload' },
{ role: 'forcereload' },
{ role: 'toggledevtools' },
{ type: 'separator' },
{ role: 'resetzoom' },
{ role: 'zoomin' },
{ role: 'zoomout' },
{ type: 'separator' },
{ role: 'togglefullscreen' }
]
});
// Windown menu
template.push({
role: 'window',
submenu: [{ role: 'minimize' }, { role: 'close' }]
});
// Help menu
template.push({
role: 'help',
submenu: [
{
label: 'Learn More',
click() {
require('electron').shell.openExternal('https://electron.atom.io');
}
}
]
});
if (process.platform === 'darwin') {
template.unshift({
label: app.getName(),
submenu: [
{ role: 'about' },
{ type: 'separator' },
{ role: 'services', submenu: [] },
{ type: 'separator' },
{ role: 'hide' },
{ role: 'hideothers' },
{ role: 'unhide' },
{ type: 'separator' },
{ role: 'quit' }
]
});
// Edit menu
template[1].submenu.push(
{ type: 'separator' },
{ label: 'Speech', submenu: [{ role: 'startspeaking' }, { role: 'stopspeaking' }] }
);
// Window menu
template[3].submenu = [{ role: 'close' }, { role: 'minimize' }, { role: 'zoom' }, { type: 'separator' }, { role: 'front' }];
}
menu = Menu.buildFromTemplate(template);
Menu.setApplicationMenu(menu);
}
如果有人遇到同样的问题,希望这对您有所帮助
对我来说,将模板常量的类型设置为 Electron.MenuItemConstructorOptions[]
就足够了。
例如:
const template: Electron.MenuItemConstructorOptions[] = [{
label: 'Edit',
submenu: [
{ role: 'undo' },
{ role: 'redo' },
{ type: 'separator' },
{ role: 'cut' },
{ role: 'copy' },
{ role: 'paste' },
{ role: 'pasteandmatchstyle' },
{ role: 'delete' },
{ role: 'selectall' }
]
},
{
label: 'View',
submenu: [
{ role: 'reload' },
{ role: 'forcereload' },
{ role: 'toggledevtools' },
{ type: 'separator' },
{ role: 'resetzoom' },
{ role: 'zoomin' },
{ role: 'zoomout' },
{ type: 'separator' },
{ role: 'togglefullscreen' }
]
},
{ role: 'window', submenu: [{ role: 'minimize' }, { role: 'close' }] },
{
role: 'help',
submenu: [{
label: 'Learn More',
click() {
require('electron').shell.openExternal('https://electron.atom.io');
}
}]
}
];
在MenuItemConstructorOptions界面中,子菜单属性定义为联合类型。因此,需要将 属性 强制转换为 MenuItemConstructorOptions 数组,以便识别推送运算符:
(windowMenu.submenu as MenuItemConstructorOptions[]).push(
{
type: 'separator',
},
{
label: 'Bring All To Front',
role: 'front'
}
);
对我来说问题是正确的角色大写:
{ role: 'forceReload' },
{ role: 'toggleDevTools' }
超过
{ role: 'forcereload' },
{ role: 'toggledevtools' }
参见docs。
当我基于 Electron 的菜单语法时,我遇到了同样的错误 Menu
example, which works fine in JavaScript but upsets TypeScript. Unfortunately the MenuItemConstructorOptions[]
cast for template
as
在 Electron 的示例中,TypeScript 似乎在三元组上运行,无法确定它们的结果类型。在我的例子中,在包含三元组的右括号后添加 as MenuItemConstructorOptions[]
让 TypeScript 意识到它们毕竟是有效的子菜单。
有效 TypeScript 中的完整 Electron 示例:
import { app, Menu, MenuItemConstructorOptions, shell } from "electron"
const isMac = process.platform === 'darwin'
const menu = Menu.buildFromTemplate(
[
// { role: 'appMenu' }
...(isMac ? [{
label: app.name,
submenu: [
{ role: 'about' },
{ type: 'separator' },
{ role: 'services' },
{ type: 'separator' },
{ role: 'hide' },
{ role: 'hideothers' },
{ role: 'unhide' },
{ type: 'separator' },
{ role: 'quit' }
]
}] : []) as MenuItemConstructorOptions[],
// { role: 'fileMenu' }
{
label: 'File',
submenu: [
isMac ? { role: 'close' } : { role: 'quit' }
] as MenuItemConstructorOptions[]
},
// { role: 'editMenu' }
{
label: 'Edit',
submenu: [
{ role: 'undo' },
{ role: 'redo' },
{ type: 'separator' },
{ role: 'cut' },
{ role: 'copy' },
{ role: 'paste' },
...(isMac ? [
{ role: 'pasteAndMatchStyle' },
{ role: 'delete' },
{ role: 'selectAll' },
{ type: 'separator' },
{
label: 'Speech',
submenu: [
{ role: 'startSpeaking' },
{ role: 'stopSpeaking' }
]
}
] : [
{ role: 'delete' },
{ type: 'separator' },
{ role: 'selectAll' }
]) as MenuItemConstructorOptions[]
]
},
// { role: 'viewMenu' }
{
label: 'View',
submenu: [
{ role: 'reload' },
{ role: 'forceReload' },
{ role: 'toggleDevTools' },
{ type: 'separator' },
{ role: 'resetZoom' },
{ role: 'zoomIn' },
{ role: 'zoomOut' },
{ type: 'separator' },
{ role: 'togglefullscreen' }
]
},
// { role: 'windowMenu' }
{
label: 'Window',
submenu: [
{ role: 'minimize' },
{ role: 'zoom' },
...(isMac ? [
{ type: 'separator' },
{ role: 'front' },
{ type: 'separator' },
{ role: 'window' }
] : [
{ role: 'close' }
]) as MenuItemConstructorOptions[]
]
},
{
role: 'help',
submenu: [
{
label: 'Learn More',
click: async () => {
await shell.openExternal('https://electronjs.org')
}
}
]
}
]
)
Menu.setApplicationMenu(menu)