From aefe9ed69fb791eabb56a1ac8937df3d65abe5cc Mon Sep 17 00:00:00 2001 From: chioarub Date: Thu, 4 Jun 2026 09:32:24 +0300 Subject: [PATCH] fix(typecheck): add proper type parameters to useState(null) hooks When useState(null) is used for state that later accepts string, boolean, or number values, TypeScript infers the state type as null, making the setter reject non-null values (TS2345, TS2322). This adds explicit type parameters to 11 files in the simplest cases: string, boolean, number, and known string unions. components/mcp/MCPReconnect.tsx string | null commands/btw/btw.tsx string | null (error + response) commands/tag/tag.tsx string | null (sessionId) commands/rate-limit-options/ ReactNode | null commands/thinkback/thinkback.tsx string | null, boolean | null components/TeleportError.tsx TeleportLocalErrorType | null components/TeleportRepoMismatchDialog string | null components/DesktopHandoff.tsx string | null components/ThinkingToggle.tsx boolean | null components/AutoUpdaterWrapper.tsx boolean | null (2 states) components/PromptInputFooterLeftSide number | null Complex object types (GroveConfig, EnvironmentResource, etc.) and deeply multi-state components (LogSelector, PluginSettings, Doctor) are deferred to follow-up PRs. Refs: #1486 --- src/commands/btw/btw.tsx | 4 ++-- src/commands/rate-limit-options/rate-limit-options.tsx | 2 +- src/commands/tag/tag.tsx | 2 +- src/commands/thinkback/thinkback.tsx | 6 +++--- src/components/AutoUpdaterWrapper.tsx | 4 ++-- src/components/DesktopHandoff.tsx | 2 +- src/components/PromptInput/PromptInputFooterLeftSide.tsx | 2 +- src/components/TeleportError.tsx | 2 +- src/components/TeleportRepoMismatchDialog.tsx | 2 +- src/components/ThinkingToggle.tsx | 2 +- src/components/mcp/MCPReconnect.tsx | 2 +- 11 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/commands/btw/btw.tsx b/src/commands/btw/btw.tsx index 8ce8007cae..fb69b925ba 100644 --- a/src/commands/btw/btw.tsx +++ b/src/commands/btw/btw.tsx @@ -40,8 +40,8 @@ function BtwSideQuestion(t0) { context, onDone } = t0; - const [response, setResponse] = useState(null); - const [error, setError] = useState(null); + const [response, setResponse] = useState(null); + const [error, setError] = useState(null); const [frame, setFrame] = useState(0); const scrollRef = useRef(null); const { diff --git a/src/commands/rate-limit-options/rate-limit-options.tsx b/src/commands/rate-limit-options/rate-limit-options.tsx index ce8ad3dec2..77827b0952 100644 --- a/src/commands/rate-limit-options/rate-limit-options.tsx +++ b/src/commands/rate-limit-options/rate-limit-options.tsx @@ -27,7 +27,7 @@ function RateLimitOptionsMenu(t0) { onDone, context } = t0; - const [subCommandJSX, setSubCommandJSX] = useState(null); + const [subCommandJSX, setSubCommandJSX] = useState(null); const claudeAiLimits = useClaudeAiLimits(); let t1; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { diff --git a/src/commands/tag/tag.tsx b/src/commands/tag/tag.tsx index d726cda351..29c1283543 100644 --- a/src/commands/tag/tag.tsx +++ b/src/commands/tag/tag.tsx @@ -76,7 +76,7 @@ function ToggleTagAndClose(t0) { onDone } = t0; const [showConfirm, setShowConfirm] = React.useState(false); - const [sessionId, setSessionId] = React.useState(null); + const [sessionId, setSessionId] = React.useState(null); let t1; if ($[0] !== tagName) { t1 = recursivelySanitizeUnicode(tagName).trim(); diff --git a/src/commands/thinkback/thinkback.tsx b/src/commands/thinkback/thinkback.tsx index 174710509a..709cfadb47 100644 --- a/src/commands/thinkback/thinkback.tsx +++ b/src/commands/thinkback/thinkback.tsx @@ -390,9 +390,9 @@ function ThinkbackFlow(t0) { onDone } = t0; const [installComplete, setInstallComplete] = useState(false); - const [installError, setInstallError] = useState(null); - const [skillDir, setSkillDir] = useState(null); - const [hasGenerated, setHasGenerated] = useState(null); + const [installError, setInstallError] = useState(null); + const [skillDir, setSkillDir] = useState(null); + const [hasGenerated, setHasGenerated] = useState(null); let t1; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { t1 = function handleReady() { diff --git a/src/components/AutoUpdaterWrapper.tsx b/src/components/AutoUpdaterWrapper.tsx index b0911ab112..9c38082088 100644 --- a/src/components/AutoUpdaterWrapper.tsx +++ b/src/components/AutoUpdaterWrapper.tsx @@ -26,8 +26,8 @@ export function AutoUpdaterWrapper(t0) { showSuccessMessage, verbose } = t0; - const [useNativeInstaller, setUseNativeInstaller] = React.useState(null); - const [isPackageManager, setIsPackageManager] = React.useState(null); + const [useNativeInstaller, setUseNativeInstaller] = React.useState(null); + const [isPackageManager, setIsPackageManager] = React.useState(null); let t1; let t2; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { diff --git a/src/components/DesktopHandoff.tsx b/src/components/DesktopHandoff.tsx index c739bebc02..e4fb8d9444 100644 --- a/src/components/DesktopHandoff.tsx +++ b/src/components/DesktopHandoff.tsx @@ -30,7 +30,7 @@ export function DesktopHandoff(t0) { onDone } = t0; const [state, setState] = useState("checking"); - const [error, setError] = useState(null); + const [error, setError] = useState(null); const [downloadMessage, setDownloadMessage] = useState(""); let t1; if ($[0] !== error || $[1] !== onDone || $[2] !== state) { diff --git a/src/components/PromptInput/PromptInputFooterLeftSide.tsx b/src/components/PromptInput/PromptInputFooterLeftSide.tsx index a975fa7b82..fa45919c6c 100644 --- a/src/components/PromptInput/PromptInputFooterLeftSide.tsx +++ b/src/components/PromptInput/PromptInputFooterLeftSide.tsx @@ -74,7 +74,7 @@ type Props = { function ProactiveCountdown() { const $ = _c(7); const nextTickAt = useSyncExternalStore(proactiveModule?.subscribeToProactiveChanges ?? NO_OP_SUBSCRIBE, proactiveModule?.getNextTickAt ?? NULL, NULL); - const [remainingSeconds, setRemainingSeconds] = useState(null); + const [remainingSeconds, setRemainingSeconds] = useState(null); let t0; let t1; if ($[0] !== nextTickAt) { diff --git a/src/components/TeleportError.tsx b/src/components/TeleportError.tsx index 8a8634c4fb..f0cf4d9677 100644 --- a/src/components/TeleportError.tsx +++ b/src/components/TeleportError.tsx @@ -25,7 +25,7 @@ export function TeleportError(t0) { errorsToIgnore: t1 } = t0; const errorsToIgnore = t1 === undefined ? EMPTY_ERRORS_TO_IGNORE : t1; - const [currentError, setCurrentError] = useState(null); + const [currentError, setCurrentError] = useState(null); const [isLoggingIn, setIsLoggingIn] = useState(false); let t2; if ($[0] !== errorsToIgnore || $[1] !== onComplete) { diff --git a/src/components/TeleportRepoMismatchDialog.tsx b/src/components/TeleportRepoMismatchDialog.tsx index 665322faee..2ae3c8b17e 100644 --- a/src/components/TeleportRepoMismatchDialog.tsx +++ b/src/components/TeleportRepoMismatchDialog.tsx @@ -21,7 +21,7 @@ export function TeleportRepoMismatchDialog(t0) { onCancel } = t0; const [availablePaths, setAvailablePaths] = useState(initialPaths); - const [errorMessage, setErrorMessage] = useState(null); + const [errorMessage, setErrorMessage] = useState(null); const [validating, setValidating] = useState(false); let t1; if ($[0] !== availablePaths || $[1] !== onCancel || $[2] !== onSelectPath || $[3] !== targetRepo) { diff --git a/src/components/ThinkingToggle.tsx b/src/components/ThinkingToggle.tsx index e9a2255b28..8ae6a69be6 100644 --- a/src/components/ThinkingToggle.tsx +++ b/src/components/ThinkingToggle.tsx @@ -25,7 +25,7 @@ export function ThinkingToggle(t0) { isMidConversation } = t0; const exitState = useExitOnCtrlCDWithKeybindings(); - const [confirmationPending, setConfirmationPending] = useState(null); + const [confirmationPending, setConfirmationPending] = useState(null); let t1; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { t1 = [{ diff --git a/src/components/mcp/MCPReconnect.tsx b/src/components/mcp/MCPReconnect.tsx index 8b3f9616d6..9f8ddda980 100644 --- a/src/components/mcp/MCPReconnect.tsx +++ b/src/components/mcp/MCPReconnect.tsx @@ -22,7 +22,7 @@ export function MCPReconnect(t0) { const store = useAppStateStore(); const reconnectMcpServer = useMcpReconnect(); const [isReconnecting, setIsReconnecting] = useState(true); - const [error, setError] = useState(null); + const [error, setError] = useState(null); let t1; let t2; if ($[0] !== onComplete || $[1] !== reconnectMcpServer || $[2] !== serverName || $[3] !== store) {