Road to No Explicit Any Part 9 (#8498)

## Summary

This PR removes `any` types from core source files and replaces them
with proper TypeScript types.

### Key Changes

#### Type Safety Improvements
- Replaced `any` with `unknown`, explicit types, or proper interfaces
across core files
- Introduced new type definitions: `SceneConfig`, `Load3DNode`,
`ElectronWindow`
- Used `Object.assign` instead of `as any` for dynamic property
assignment
- Replaced `as any` casts with proper type assertions

### Files Changed

Source files:
- src/extensions/core/widgetInputs.ts - Removed unnecessary `as any`
cast
- src/platform/cloud/onboarding/auth.ts - Used `Record<string, unknown>`
and Sentry types
- src/platform/telemetry/providers/cloud/MixpanelTelemetryProvider.ts -
Used `AuditLog[]` type
- src/platform/workflow/management/stores/workflowStore.ts - Used
`typeof ComfyWorkflow` constructor type
- src/scripts/app.ts - Used `ResultItem[]` for Clipspace images
- src/services/colorPaletteService.ts - Used `Object.assign` instead of
`as any`
- src/services/customerEventsService.ts - Used `unknown` instead of
`any`
- src/services/load3dService.ts - Added proper interface types for
Load3D nodes
- src/types/litegraph-augmentation.d.ts - Used `TWidgetValue[]` type
- src/utils/envUtil.ts - Added ElectronWindow interface
- src/workbench/extensions/manager/stores/comfyManagerStore.ts - Typed
event as `CustomEvent<{ ui_id?: string }>`

### Testing
- All TypeScript type checking passes (`pnpm typecheck`)
- Linting passes without errors (`pnpm lint`)
- Code formatting applied (`pnpm format`)

Part of the "Road to No Explicit Any" initiative.

### Previous PRs in this series:
- Part 2: #7401
- Part 3: #7935
- Part 4: #7970
- Part 5: #8064
- Part 6: #8083
- Part 7: #8092
- Part 8 Group 1: #8253
- Part 8 Group 2: #8258
- Part 8 Group 3: #8304
- Part 8 Group 4: #8314
- Part 8 Group 5: #8329
- Part 8 Group 6: #8344
- Part 8 Group 7: #8459
- Part 8 Group 8: #8496
- Part 9: #8498 (this PR)
This commit is contained in:
Johnpaul Chiwetelu
2026-02-02 17:30:49 +01:00
committed by GitHub
parent cfdd002b7c
commit 2f8bd7b04f
11 changed files with 69 additions and 40 deletions

View File

@@ -110,7 +110,7 @@ export class PrimitiveNode extends LGraphNode {
for (let i = 0; i < this.widgets_values.length; i++) {
const w = this.widgets[i]
if (w) {
w.value = this.widgets_values[i] as any
w.value = this.widgets_values[i]
}
}
}

View File

@@ -18,9 +18,9 @@ function captureApiError(
errorType: 'http_error' | 'network_error',
httpStatus?: number,
operation?: string,
extraContext?: Record<string, any>
extraContext?: Record<string, unknown>
) {
const tags: Record<string, any> = {
const tags: Record<string, string | number> = {
api_endpoint: endpoint,
error_type: errorType
}
@@ -33,7 +33,7 @@ function captureApiError(
tags.operation = operation
}
const sentryOptions: any = {
const sentryOptions: Sentry.ExclusiveEventHintOrCaptureContext = {
tags,
extra: extraContext ? { ...extraContext } : undefined
}

View File

@@ -8,6 +8,7 @@ import {
startTopupTracking as startTopupUtil
} from '@/platform/telemetry/topupTracker'
import { useWorkflowStore } from '@/platform/workflow/management/stores/workflowStore'
import type { AuditLog } from '@/services/customerEventsService'
import { useWorkflowTemplatesStore } from '@/platform/workflow/templates/repositories/workflowTemplatesStore'
import { app } from '@/scripts/app'
import { useNodeDefStore } from '@/stores/nodeDefStore'
@@ -261,7 +262,7 @@ export class MixpanelTelemetryProvider implements TelemetryProvider {
startTopupUtil()
}
checkForCompletedTopup(events: any[] | undefined | null): boolean {
checkForCompletedTopup(events: AuditLog[] | undefined | null): boolean {
return checkTopupUtil(events)
}

View File

@@ -387,11 +387,12 @@ export const useWorkflowStore = defineStore('workflow', () => {
) as ComfyWorkflowJSON
state.id = id
const workflow: ComfyWorkflow = new (existingWorkflow.constructor as any)({
path,
modified: Date.now(),
size: -1
})
const workflow: ComfyWorkflow =
new (existingWorkflow.constructor as typeof ComfyWorkflow)({
path,
modified: Date.now(),
size: -1
})
workflow.originalContent = workflow.content = JSON.stringify(state)
workflowLookup.value[workflow.path] = workflow
return workflow

View File

@@ -123,7 +123,7 @@ type Clipspace = {
widgets?: Pick<IBaseWidget, 'type' | 'name' | 'value'>[] | null
imgs?: HTMLImageElement[] | null
original_imgs?: HTMLImageElement[] | null
images?: any[] | null
images?: ResultItem[] | null
selectedIndex: number
img_paste_mode: string
paintedIndex: number

View File

@@ -161,22 +161,25 @@ export const useColorPaletteService = () => {
}
app.canvas._pattern = undefined
for (const [key, value] of Object.entries(palette)) {
if (Object.prototype.hasOwnProperty.call(LiteGraph, key)) {
if (key === 'NODE_DEFAULT_SHAPE' && typeof value === 'string') {
console.warn(
`litegraph_base.NODE_DEFAULT_SHAPE only accepts [${[
LiteGraph.BOX_SHAPE,
LiteGraph.ROUND_SHAPE,
LiteGraph.CARD_SHAPE
].join(', ')}] but got ${value}`
)
LiteGraph.NODE_DEFAULT_SHAPE = LiteGraph.ROUND_SHAPE
} else {
;(LiteGraph as any)[key] = value
}
}
if (typeof palette.NODE_DEFAULT_SHAPE === 'string')
console.warn(
`litegraph_base.NODE_DEFAULT_SHAPE only accepts [${[
LiteGraph.BOX_SHAPE,
LiteGraph.ROUND_SHAPE,
LiteGraph.CARD_SHAPE
].join(', ')}] but got ${palette.NODE_DEFAULT_SHAPE}`
)
const default_shape =
typeof palette.NODE_DEFAULT_SHAPE === 'string'
? LiteGraph.ROUND_SHAPE
: palette.NODE_DEFAULT_SHAPE
const sanitizedPalette: Partial<typeof LiteGraph> = {
...palette,
NODE_DEFAULT_SHAPE: default_shape
}
Object.assign(LiteGraph, sanitizedPalette)
}
/**

View File

@@ -122,7 +122,7 @@ export const useCustomerEventsService = () => {
.join(' ')
}
function formatJsonValue(value: any) {
function formatJsonValue(value: unknown) {
if (typeof value === 'number') {
// Format numbers with commas and decimals if needed
return value.toLocaleString()

View File

@@ -7,6 +7,15 @@ import type Load3d from '@/extensions/core/load3d/Load3d'
import type { LGraphNode } from '@/lib/litegraph/src/litegraph'
import type { NodeId } from '@/platform/workflow/validation/schemas/workflowSchema'
// Type definitions for Load3D node
interface SceneConfig {
backgroundImage?: string
}
interface Load3DNode extends LGraphNode {
syncLoad3dConfig?: () => void
}
const viewerInstances = new Map<NodeId, any>()
export class Load3dService {
@@ -139,7 +148,9 @@ export class Load3dService {
.getCurrentBackgroundInfo()
if (sourceBackgroundInfo.type === 'image') {
const sourceNode = this.getNodeByLoad3d(source)
const sceneConfig = sourceNode?.properties?.['Scene Config'] as any
const sceneConfig = sourceNode?.properties?.['Scene Config'] as
| SceneConfig
| undefined
const backgroundPath = sceneConfig?.backgroundImage
if (backgroundPath) {
await target.setBackgroundImage(backgroundPath)
@@ -179,8 +190,9 @@ export class Load3dService {
await viewer.applyChanges()
// Sync configuration back to the node's UI
if ((node as any).syncLoad3dConfig) {
;(node as any).syncLoad3dConfig()
const load3DNode = node as Load3DNode
if (load3DNode.syncLoad3dConfig) {
load3DNode.syncLoad3dConfig()
}
}

View File

@@ -5,7 +5,10 @@ import type {
LLink,
Size
} from '@/lib/litegraph/src/litegraph'
import type { IBaseWidget } from '@/lib/litegraph/src/types/widgets'
import type {
IBaseWidget,
TWidgetValue
} from '@/lib/litegraph/src/types/widgets'
import type { NodeId } from '@/platform/workflow/validation/schemas/workflowSchema'
import type { NodeExecutionOutput } from '@/schemas/apiSchema'
import type { ComfyNodeDef as ComfyNodeDefV2 } from '@/schemas/nodeDef/nodeDefSchemaV2'
@@ -210,6 +213,6 @@ declare module '@/lib/litegraph/src/litegraph' {
* used by litegraph internally. We should remove the dependency on it later.
*/
interface LGraphNode {
widgets_values?: unknown[]
widgets_values?: TWidgetValue[]
}
}

View File

@@ -1,11 +1,16 @@
import type { ElectronAPI } from '@comfyorg/comfyui-electron-types'
// Extend Window interface to include electronAPI
type ElectronWindow = typeof window & {
electronAPI?: ElectronAPI
}
export function isElectron() {
return 'electronAPI' in window && window.electronAPI !== undefined
}
export function electronAPI() {
return (window as any).electronAPI as ElectronAPI
return (window as ElectronWindow).electronAPI as ElectronAPI
}
export function showNativeSystemMenu() {

View File

@@ -59,14 +59,18 @@ export const useComfyManagerStore = defineStore('comfyManager', () => {
const managerQueue = useManagerQueue(taskHistory, taskQueue, installedPacks)
// Listen for task completion events to clean up installing state
useEventListener(app.api, 'cm-task-completed', (event: any) => {
const taskId = event.detail?.ui_id
if (taskId && taskIdToPackId.value.has(taskId)) {
const packId = taskIdToPackId.value.get(taskId)!
installingPacksIds.value.delete(packId)
taskIdToPackId.value.delete(taskId)
useEventListener(
app.api,
'cm-task-completed',
(event: CustomEvent<{ ui_id?: string }>) => {
const taskId = event.detail?.ui_id
if (taskId && taskIdToPackId.value.has(taskId)) {
const packId = taskIdToPackId.value.get(taskId)!
installingPacksIds.value.delete(packId)
taskIdToPackId.value.delete(taskId)
}
}
})
)
const setStale = () => {
isStale.value = true