Skip to content
This repository was archived by the owner on Jul 17, 2026. It is now read-only.

🐞 fix: 修复as any类型问题 - #802

Merged
imsyy merged 6 commits into
devfrom
dev-cy-fix
Feb 2, 2026
Merged

imsyy merged 6 commits into
devfrom
dev-cy-fix

Conversation

@kazukokawagawa

Copy link
Copy Markdown
Collaborator

No description provided.

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello @kazukokawagawa, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request primarily focuses on enhancing the type safety of the application by systematically replacing generic as any type assertions with more precise type definitions. This refactoring improves code clarity, reduces potential runtime errors, and provides better developer experience through stronger static analysis. Additionally, it includes minor configuration adjustments for native modules.

Highlights

  • Type Safety Improvements: Replaced numerous as any type assertions with more specific types or removed them where type inference was sufficient across various modules, including IPC handlers, Netease API integration, and Vue directives.
  • NAPI Module Configuration Update: Updated package.json files for external-media-integration and taskbar-lyric NAPI modules, specifically changing binaryName to use underscores instead of hyphens and adding a main field for external-media-integration.
  • Robust Error Handling and Event Subscription: Enhanced error handling in the Netease API integration by explicitly typing caught errors and improved the PlayerController's setting subscription logic for better type safety and robustness when accessing event properties.
  • Custom Directive Type Definitions: Introduced dedicated interfaces (HTMLElementWithDebounce, HTMLElementWithThrottle) to properly type custom properties added to HTMLElement for debounce and throttle directives, and corrected the DirectiveBinding type.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

本次 PR 提交的代码变更非常出色,系统性地移除了多处 as any 类型断言,显著提升了代码的类型安全性和可维护性。通过使用更具体的类型、类型守卫以及扩展接口,代码变得更加健壮和清晰。这是一个高质量的重构。我只发现了一个与 unknown 类型处理相关的小问题,并提供了修复建议。整体而言,这是一次非常棒的改进!

Comment thread electron/server/netease/index.ts Outdated
Comment on lines +51 to +57
const err = error as { status: number; body: unknown; message?: string };
if ([400, 301].includes(err.status)) {
return reply.status(err.status).send(err.body);
}
return reply
.status(500)
.send(error.body || { error: error.message || "Internal Server Error" });
.send(err.body || { error: err.message || "Internal Server Error" });

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

虽然改用 unknown 是很好的类型安全实践,但随后的 error as ... 类型断言是不安全的。如果 error 不是预期的对象结构(例如,null 或一个字符串),在访问 err.status 时会引发运行时错误。建议在访问属性前添加类型守卫,以确保 error 是一个对象。

      if (typeof error === 'object' && error) {
        const err = error as { status: number; body: unknown; message?: string };
        if ([400, 301].includes(err.status)) {
          return reply.status(err.status).send(err.body);
        }
        return reply
          .status(500)
          .send(err.body || { error: err.message || "Internal Server Error" });
      }
      return reply.status(500).send({ error: String(error) });

@kazukokawagawa

Copy link
Copy Markdown
Collaborator Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

这次的 Pull Request 在提升代码库的类型安全方面做得非常出色,移除了大量的 as any 类型断言,并替换为更具体的类型或更安全的类型守卫。为更好的错误报告和日志记录而引入的 GlobalErrorHandler 组件和控制台缓冲逻辑是一个很有价值的新功能。PlayerController.ts 和 electron/server/netease/index.ts 中的改动是编写更健壮、类型更安全代码的绝佳范例。

我主要想提出的反馈是关于代码重复。在 src/utils/initIpc.ts 中新增的控制台缓冲逻辑与 src/utils/log.ts 中引入的 createConsoleBuffer 工具函数几乎完全相同。我留下了一条建议,建议重构 initIpc.ts 以使用这个新的可复用工具函数,这将使代码更清晰、更易于维护。

Comment thread src/utils/initIpc.ts Outdated
Comment on lines +13 to +97
type ConsoleWithBuffer = Console & { __splayerConsoleBuffer?: boolean };

const consoleBuffer: string[] = [];
const maxConsoleBufferSize = 500;

const formatConsoleValue = (value: unknown) => {
if (value instanceof Error) return value.stack || value.message;
if (typeof value === "string") return value;
if (typeof value === "number") return String(value);
if (typeof value === "boolean") return value ? "true" : "false";
if (typeof value === "bigint") return value.toString();
if (typeof value === "function") return value.name ? `[Function ${value.name}]` : "[Function]";
if (value === undefined) return "undefined";
if (value === null) return "null";
try {
return JSON.stringify(value);
} catch {
return String(value);
}
};

const pushConsoleLog = (level: string, args: unknown[]) => {
const time = new Date().toISOString();
const message = args.map(formatConsoleValue).join(" ");
consoleBuffer.push(`[${time}] [${level}] ${message}`);
if (consoleBuffer.length > maxConsoleBufferSize) {
consoleBuffer.splice(0, consoleBuffer.length - maxConsoleBufferSize);
}
};

const formatErrorEventMessage = (event: ErrorEvent | PromiseRejectionEvent) => {
if (event instanceof ErrorEvent) {
if (event.error instanceof Error) return event.error.stack || event.error.message;
return event.message || "Unknown Error";
}
const reason = event.reason;
if (reason instanceof Error) return reason.stack || reason.message;
if (typeof reason === "string") return reason;
try {
return JSON.stringify(reason);
} catch {
return String(reason);
}
};

const initConsoleBuffer = () => {
if (!isElectron) return;
const consoleWithBuffer = console as ConsoleWithBuffer;
if (consoleWithBuffer.__splayerConsoleBuffer) return;
consoleWithBuffer.__splayerConsoleBuffer = true;

const originalLog = console.log.bind(console);
const originalInfo = console.info.bind(console);
const originalWarn = console.warn.bind(console);
const originalError = console.error.bind(console);
const originalDebug = console.debug.bind(console);

console.log = (...args) => {
pushConsoleLog("log", args);
originalLog(...args);
};
console.info = (...args) => {
pushConsoleLog("info", args);
originalInfo(...args);
};
console.warn = (...args) => {
pushConsoleLog("warn", args);
originalWarn(...args);
};
console.error = (...args) => {
pushConsoleLog("error", args);
originalError(...args);
};
console.debug = (...args) => {
pushConsoleLog("debug", args);
originalDebug(...args);
};

window.addEventListener("error", (event) => {
pushConsoleLog("error", [formatErrorEventMessage(event)]);
});
window.addEventListener("unhandledrejection", (event) => {
pushConsoleLog("error", [formatErrorEventMessage(event)]);
});
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

这里存在大量的代码重复。formatConsoleValue、formatErrorEventMessage 函数以及 initConsoleBuffer 内部的逻辑,与 src/utils/log.ts 文件中新增的 createConsoleBuffer 工具函数几乎完全相同。

为了提高代码的可维护性并减少冗余,建议重构此处的实现,统一使用 createConsoleBuffer 工具函数。这需要移除这部分重复的代码,并修改 initIpc 函数来使用导入的工具函数。

例如,你可以在 initIpc 中这样实现:

import { createConsoleBuffer } from "./log";
// ...

const consoleBuffer = createConsoleBuffer({
  bufferKey: "__splayerGlobalConsoleBuffer",
});
consoleBuffer.init();

// 为未捕获的错误添加监听器
window.addEventListener("error", (event) => {
  consoleBuffer.push("error", [consoleBuffer.formatErrorEventMessage(event)]);
});
window.addEventListener("unhandledrejection", (event) => {
  consoleBuffer.push("error", [consoleBuffer.formatErrorEventMessage(event)]);
});

// ... 在文件后面
window.electron.ipcRenderer.on("request-renderer-console-logs", () => {
  window.electron.ipcRenderer.send("return-renderer-console-logs", consoleBuffer.getLogs());
});

这种方法复用了 log.ts 中的逻辑,遵循了 DRY (Don't Repeat Yourself) 原则。

@imsyy
imsyy merged commit c9a1600 into dev Feb 2, 2026
4 checks passed
@kazukokawagawa
kazukokawagawa deleted the dev-cy-fix branch February 2, 2026 09:21
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants