Remove and forbid @ts-expect-error (#36513)

Removes `@ts-expect-error` in the code base and forbids it.

---------

Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: silverwind <115237+silverwind@users.noreply.github.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
Copilot
2026-02-02 01:00:34 +08:00
committed by GitHub
parent c2dea22926
commit 7883f6dde9
22 changed files with 170 additions and 117 deletions

View File

@@ -41,7 +41,6 @@ export async function initCaptcha() {
// * the INPUT_NAME is a "const", it should not be changed.
// * the "mCaptcha.default" is actually the "Widget".
// @ts-expect-error TS2540: Cannot assign to 'INPUT_NAME' because it is a read-only property.
mCaptcha.INPUT_NAME = 'm-captcha-response';
const instanceURL = captchaEl.getAttribute('data-instance-url')!;

View File

@@ -6,13 +6,9 @@ const {pageData} = window.config;
async function initInputCitationValue(citationCopyApa: HTMLButtonElement, citationCopyBibtex: HTMLButtonElement) {
const [{Cite, plugins}] = await Promise.all([
// @ts-expect-error: module exports no types
import(/* webpackChunkName: "citation-js-core" */'@citation-js/core'),
// @ts-expect-error: module exports no types
import(/* webpackChunkName: "citation-js-formats" */'@citation-js/plugin-software-formats'),
// @ts-expect-error: module exports no types
import(/* webpackChunkName: "citation-js-bibtex" */'@citation-js/plugin-bibtex'),
// @ts-expect-error: module exports no types
import(/* webpackChunkName: "citation-js-csl" */'@citation-js/plugin-csl'),
]);
const {citationFileContent} = pageData;

View File

@@ -72,10 +72,9 @@ class Source {
const sourcesByUrl = new Map<string, Source | null>();
const sourcesByPort = new Map<MessagePort, Source | null>();
// @ts-expect-error: typescript bug?
self.addEventListener('connect', (e: MessageEvent) => {
(self as unknown as SharedWorkerGlobalScope).addEventListener('connect', (e: MessageEvent) => {
for (const port of e.ports) {
port.addEventListener('message', (event) => {
port.addEventListener('message', (event: MessageEvent) => {
if (!self.EventSource) {
// some browsers (like PaleMoon, Firefox<53) don't support EventSource in SharedWorkerGlobalScope.
// this event handler needs EventSource when doing "new Source(url)", so just post a message back to the caller,

View File

@@ -56,8 +56,7 @@ function initRepoDiffConversationForm() {
const idx = newConversationHolder.getAttribute('data-idx');
form.closest('.conversation-holder')!.replaceWith(newConversationHolder);
// @ts-expect-error -- prevent further usage of the form because it should have been replaced
form = null;
(form as any) = null; // prevent further usage of the form because it should have been replaced
if (trLineType) {
// if there is a line-type for the "tr", it means the form is on the diff page

View File

@@ -201,7 +201,7 @@ async function pinMoveEnd(e: SortableEvent) {
}
async function initIssuePinSort() {
const pinDiv = document.querySelector('#issue-pins');
const pinDiv = document.querySelector<HTMLElement>('#issue-pins');
if (pinDiv === null) return;

View File

@@ -38,7 +38,7 @@ async function moveIssue({item, from, to, oldIndex}: SortableEvent): Promise<voi
async function initRepoProjectSortable(): Promise<void> {
// the HTML layout is: #project-board.board > .project-column .cards > .issue-card
const mainBoard = document.querySelector('#project-board')!;
const mainBoard = document.querySelector<HTMLElement>('#project-board')!;
let boardColumns = mainBoard.querySelectorAll<HTMLElement>('.project-column');
createSortable(mainBoard, {
group: 'project-column',
@@ -67,7 +67,7 @@ async function initRepoProjectSortable(): Promise<void> {
});
for (const boardColumn of boardColumns) {
const boardCardList = boardColumn.querySelector('.cards')!;
const boardCardList = boardColumn.querySelector<HTMLElement>('.cards')!;
createSortable(boardCardList, {
group: 'shared',
onAdd: moveIssue, // eslint-disable-line @typescript-eslint/no-misused-promises

View File

@@ -56,12 +56,11 @@ describe('Repository Branch Settings', () => {
vi.mocked(POST).mockResolvedValue({ok: true} as Response);
// Mock createSortable to capture and execute the onEnd callback
vi.mocked(createSortable).mockImplementation(async (_el: Element, options: SortableOptions | undefined) => {
vi.mocked(createSortable).mockImplementation(async (_el: HTMLElement, options: SortableOptions | undefined) => {
if (options?.onEnd) {
options.onEnd(new Event('SortableEvent') as SortableEvent);
}
// @ts-expect-error: mock is incomplete
return {destroy: vi.fn()} as Sortable;
return {destroy: vi.fn()} as unknown as Sortable;
});
initRepoSettingsBranchesDrag();

View File

@@ -4,7 +4,7 @@ import {showErrorToast} from '../modules/toast.ts';
import {queryElemChildren} from '../utils/dom.ts';
export function initRepoSettingsBranchesDrag() {
const protectedBranchesList = document.querySelector('#protected-branches-list');
const protectedBranchesList = document.querySelector<HTMLElement>('#protected-branches-list');
if (!protectedBranchesList) return;
createSortable(protectedBranchesList, {

View File

@@ -1,51 +1,52 @@
import {emojiKeys, emojiHTML, emojiString} from './emoji.ts';
import {html, htmlRaw} from '../utils/html.ts';
type TributeItem = Record<string, any>;
import type {TributeCollection} from 'tributejs';
export async function attachTribute(element: HTMLElement) {
const {default: Tribute} = await import(/* webpackChunkName: "tribute" */'tributejs');
const collections = [
{ // emojis
trigger: ':',
requireLeadingSpace: true,
values: (query: string, cb: (matches: Array<string>) => void) => {
const matches = [];
for (const name of emojiKeys) {
if (name.includes(query)) {
matches.push(name);
if (matches.length > 5) break;
}
const emojiCollection: TributeCollection<string> = { // emojis
trigger: ':',
requireLeadingSpace: true,
values: (query: string, cb: (matches: Array<string>) => void) => {
const matches = [];
for (const name of emojiKeys) {
if (name.includes(query)) {
matches.push(name);
if (matches.length > 5) break;
}
cb(matches);
},
lookup: (item: TributeItem) => item,
selectTemplate: (item: TributeItem) => {
if (item === undefined) return null;
return emojiString(item.original);
},
menuItemTemplate: (item: TributeItem) => {
return html`<div class="tribute-item">${htmlRaw(emojiHTML(item.original))}<span>${item.original}</span></div>`;
},
}, { // mentions
values: window.config.mentionValues,
requireLeadingSpace: true,
menuItemTemplate: (item: TributeItem) => {
const fullNameHtml = item.original.fullname && item.original.fullname !== '' ? html`<span class="fullname">${item.original.fullname}</span>` : '';
return html`
<div class="tribute-item">
<img alt src="${item.original.avatar}" width="21" height="21"/>
<span class="name">${item.original.name}</span>
${htmlRaw(fullNameHtml)}
</div>
`;
},
}
cb(matches);
},
];
lookup: (item) => item,
selectTemplate: (item) => {
if (item === undefined) return '';
return emojiString(item.original) ?? '';
},
menuItemTemplate: (item) => {
return html`<div class="tribute-item">${htmlRaw(emojiHTML(item.original))}<span>${item.original}</span></div>`;
},
};
// @ts-expect-error TS2351: This expression is not constructable (strange, why)
const tribute = new Tribute({collection: collections, noMatchTemplate: ''});
const mentionCollection: TributeCollection<Record<string, any>> = {
values: window.config.mentionValues,
requireLeadingSpace: true,
menuItemTemplate: (item) => {
const fullNameHtml = item.original.fullname && item.original.fullname !== '' ? html`<span class="fullname">${item.original.fullname}</span>` : '';
return html`
<div class="tribute-item">
<img alt src="${item.original.avatar}" width="21" height="21"/>
<span class="name">${item.original.name}</span>
${htmlRaw(fullNameHtml)}
</div>
`;
},
};
const tribute = new Tribute({
collection: [emojiCollection as TributeCollection<any>, mentionCollection],
noMatchTemplate: () => '',
});
tribute.attach(element);
return tribute;
}