chore(ts): enable noFallthroughCasesInSwitch and noImplicitOverride (#577)

Turn on both compiler checks in the root TypeScript configuration, which
apps/web, apps/api, apps/extension, packages/shared and packages/plugin-api
extend, and in the separate Expo configuration of apps/mobile.

No switch statement falls through today. The 19 members that override a
base class member (React error boundaries, the local database recovery
error and the vendored poster badge) now declare `override`; this only
changes type checking and is erased from the emitted JavaScript.
This commit is contained in:
Dariusz Koryto authored and GitHub committed 2026-10-15 21:54:59 +08:00
1 parent ffff9ac2a1
commit 3e54226110
8 files changed
+23 -19

No files matched your search

+2
View File
@@ -3,6 +3,8 @@
"compilerOptions": {
"ignoreDeprecations": "6.0",
"strict": true,
"noFallthroughCasesInSwitch": true,
"noImplicitOverride": true,
"baseUrl": ".",
"paths": {
"@/*": [
@@ -17,7 +17,7 @@ type State = {
const isChineseInterface = () => navigator.language.toLowerCase().startsWith("zh");
export class DesktopRendererErrorBoundary extends React.Component<{ children: ReactNode }, State> {
state: State = { error: null, reporting: false };
override state: State = { error: null, reporting: false };
static getDerivedStateFromError(error: unknown): Pick<State, "error"> {
const normalized = error instanceof Error ? error : new Error(String(error));
@@ -31,7 +31,7 @@ export class DesktopRendererErrorBoundary extends React.Component<{ children: Re
};
}
componentDidCatch(error: Error, info: ErrorInfo) {
override componentDidCatch(error: Error, info: ErrorInfo) {
markRendererRecoveryRequired();
const details: RendererErrorDetails = {
kind: "react-error",
@@ -56,7 +56,7 @@ export class DesktopRendererErrorBoundary extends React.Component<{ children: Re
}
};
render() {
override render() {
if (!this.state.error) return this.props.children;
const zh = isChineseInterface();
const desktop = Boolean(window.edgeeverDesktop?.isAvailable);
@@ -14,13 +14,13 @@ type State = {
const isChineseInterface = () => navigator.language.toLowerCase().startsWith("zh");
export class EditorPaneErrorBoundary extends React.Component<Props, State> {
state: State = { error: null };
override state: State = { error: null };
static getDerivedStateFromError(error: unknown): State {
return { error: error instanceof Error ? error : new Error(String(error)) };
}
componentDidCatch(error: Error, info: ErrorInfo) {
override componentDidCatch(error: Error, info: ErrorInfo) {
markRendererRecoveryRequired();
const details = {
kind: "react-error" as const,
@@ -32,7 +32,7 @@ export class EditorPaneErrorBoundary extends React.Component<Props, State> {
void window.edgeeverDesktop?.recordRendererError(details).catch(() => undefined);
}
componentDidUpdate(previousProps: Props) {
override componentDidUpdate(previousProps: Props) {
if (this.state.error && previousProps.resetKey !== this.props.resetKey) {
clearRendererRecoveryRequired();
this.setState({ error: null });
@@ -44,7 +44,7 @@ export class EditorPaneErrorBoundary extends React.Component<Props, State> {
this.setState({ error: null });
};
render() {
override render() {
if (!this.state.error) return this.props.children;
const zh = isChineseInterface();
@@ -9,17 +9,17 @@ type Props = {
type State = { failed: boolean };
export class AiSidebarErrorBoundary extends React.Component<Props, State> {
state: State = { failed: false };
override state: State = { failed: false };
static getDerivedStateFromError(): State {
return { failed: true };
}
componentDidCatch(error: Error, info: ErrorInfo) {
override componentDidCatch(error: Error, info: ErrorInfo) {
console.error("Caught AI sidebar error", error, info.componentStack);
}
render() {
override render() {
if (!this.state.failed) return this.props.children;
if (!this.props.open) return null;
const zh = navigator.language.toLowerCase().startsWith("zh");
+1 -1
View File
@@ -9,7 +9,7 @@ class LocalDatabaseOperationTimeoutError extends Error {
}
export class LocalDatabaseUnavailableError extends Error {
readonly cause: unknown;
override readonly cause: unknown;
constructor(cause: unknown) {
super("Browser local storage is not responding");
+5 -5
View File
@@ -21,20 +21,20 @@ export function measureLabel(text: string, size: number, weight: string, family:
}
export class BadgeBox extends Textbox {
static type = 'BadgeBox';
static customProperties = ['badgeBg', 'padX', 'padY', 'radius'];
static override type = 'BadgeBox';
static override customProperties = ['badgeBg', 'padX', 'padY', 'radius'];
declare badgeBg: string; declare padX: number; declare padY: number; declare radius: number;
constructor(text: string, options?: Partial<TextboxProps> & Partial<BadgeProps>) { super(text, { badgeBg: '#111111', padX: 0.6, padY: 0.34, radius: 0.5, editable: false, lineHeight: 1, ...options } as Partial<TextboxProps>); }
private metrics(): Metrics { return measureLabel(this.text.trim(), this.fontSize, String(this.fontWeight), this.fontFamily); }
/** Size comes from the measured label, not from Fabric's line layout. */
initDimensions(): void {
override initDimensions(): void {
const m = this.metrics(); const px = this.padX * this.fontSize, py = this.padY * this.fontSize;
this.width = m.width + px * 2; this.height = m.ascent + m.descent + py * 2;
this.textLines = [this.text]; this._textLines = [[...this.text]]; this.dirty = true;
}
/** The pill is the visible extent. Fabric's own line cache is never filled here, so its version would throw. */
getLineWidth(): number { return this.width; }
_render(c: CanvasRenderingContext2D): void {
override getLineWidth(): number { return this.width; }
override _render(c: CanvasRenderingContext2D): void {
const w = this.width, h = this.height; const m = this.metrics(); const r = Math.min(h / 2, this.radius * h);
c.save(); c.fillStyle = this.badgeBg; c.beginPath();
c.moveTo(-w / 2 + r, -h / 2); c.arcTo(w / 2, -h / 2, w / 2, h / 2, r); c.arcTo(w / 2, h / 2, -w / 2, h / 2, r); c.arcTo(-w / 2, h / 2, -w / 2, -h / 2, r); c.arcTo(-w / 2, -h / 2, w / 2, -h / 2, r); c.closePath(); c.fill();
+3 -3
View File
@@ -38,17 +38,17 @@ const returnToPreviousPage = () => {
};
class MobileEditorErrorBoundary extends React.Component<React.PropsWithChildren, MobileEditorErrorBoundaryState> {
state: MobileEditorErrorBoundaryState = { failed: false };
override state: MobileEditorErrorBoundaryState = { failed: false };
static getDerivedStateFromError(): MobileEditorErrorBoundaryState {
return { failed: true };
}
componentDidCatch(error: Error) {
override componentDidCatch(error: Error) {
console.error("Mobile editor crashed", error);
}
render() {
override render() {
if (!this.state.failed) return this.props.children;
const english = (getBrowserLocale() ?? defaultLocale) === "en-US";
return (
+2
View File
@@ -9,6 +9,8 @@
"isolatedModules": true,
"jsx": "react-jsx",
"strict": true,
"noFallthroughCasesInSwitch": true,
"noImplicitOverride": true,
"noEmit": true,
"skipLibCheck": true,
"ignoreDeprecations": "6.0",