[refactor] Type createNode options parameter (#9262)

## Summary
Narrow `CreateNodeOptions` from `Partial<Omit<LGraphNode, ...>>`
(exposing hundreds of properties/methods) to an explicit interface
listing only creation-time properties.

## Changes
- Replace `Partial<Omit<LGraphNode, 'constructor' | 'inputs' |
'outputs'>>` with explicit `CreateNodeOptions` interface containing
only: `pos`, `size`, `properties`, `flags`, `mode`, `color`, `bgcolor`,
`boxcolor`, `title`, `shape`, `inputs`, `outputs`
- Rename local `CreateNodeOptions` in `createModelNodeFromAsset.ts` to
`ModelNodeCreateOptions` to avoid collision

## Ecosystem verification
GitHub code search across ~50 repos confirms only `pos` and `outputs`
are used externally. All covered by the narrowed interface.

Fixes #9276
Fixes #4740
This commit is contained in:
Johnpaul Chiwetelu
2026-03-04 23:01:18 +01:00
committed by GitHub
parent 9e2299ca65
commit 82750d629d
6 changed files with 37 additions and 12 deletions

View File

@@ -6573,7 +6573,7 @@ export class LGraphCanvas implements CustomEventDispatcher<LGraphCanvasEventMap>
const ySizeFix = opts.posSizeFix[1] * LiteGraph.NODE_SLOT_HEIGHT const ySizeFix = opts.posSizeFix[1] * LiteGraph.NODE_SLOT_HEIGHT
const nodeX = opts.position[0] + opts.posAdd[0] + xSizeFix const nodeX = opts.position[0] + opts.posAdd[0] + xSizeFix
const nodeY = opts.position[1] + opts.posAdd[1] + ySizeFix const nodeY = opts.position[1] + opts.posAdd[1] + ySizeFix
const pos = [nodeX, nodeY] const pos: [number, number] = [nodeX, nodeY]
const newNode = LiteGraph.createNode(nodeTypeStr, nodeNewOpts?.title, { const newNode = LiteGraph.createNode(nodeTypeStr, nodeNewOpts?.title, {
pos pos
}) })

View File

@@ -10,7 +10,13 @@ import { Reroute } from './Reroute'
import { InputIndicators } from './canvas/InputIndicators' import { InputIndicators } from './canvas/InputIndicators'
import { LabelPosition, SlotDirection, SlotShape, SlotType } from './draw' import { LabelPosition, SlotDirection, SlotShape, SlotType } from './draw'
import { Rectangle } from './infrastructure/Rectangle' import { Rectangle } from './infrastructure/Rectangle'
import type { Dictionary, ISlotType, Rect, WhenNullish } from './interfaces' import type {
CreateNodeOptions,
Dictionary,
ISlotType,
Rect,
WhenNullish
} from './interfaces'
import { distance, isInsideRectangle, overlapBounding } from './measure' import { distance, isInsideRectangle, overlapBounding } from './measure'
import { SubgraphIONodeBase } from './subgraph/SubgraphIONodeBase' import { SubgraphIONodeBase } from './subgraph/SubgraphIONodeBase'
import { SubgraphSlot } from './subgraph/SubgraphSlotBase' import { SubgraphSlot } from './subgraph/SubgraphSlotBase'
@@ -525,7 +531,7 @@ export class LiteGraphGlobal {
createNode( createNode(
type: string, type: string,
title?: string, title?: string,
options?: Dictionary<unknown> options?: CreateNodeOptions
): LGraphNode | null { ): LGraphNode | null {
const base_class = this.registered_node_types[type] const base_class = this.registered_node_types[type]
if (!base_class) { if (!base_class) {
@@ -561,10 +567,7 @@ export class LiteGraphGlobal {
// extra options // extra options
if (options) { if (options) {
for (const i in options) { Object.assign(node, options)
// @ts-expect-error #577 Requires interface
node[i] = options[i]
}
} }
// callback // callback

View File

@@ -3,13 +3,17 @@ import type { CanvasPointerEvent } from '@/lib/litegraph/src/types/events'
import type { TWidgetValue } from '@/lib/litegraph/src/types/widgets' import type { TWidgetValue } from '@/lib/litegraph/src/types/widgets'
import type { ContextMenu } from './ContextMenu' import type { ContextMenu } from './ContextMenu'
import type { LGraphNode, NodeId } from './LGraphNode' import type { LGraphNode, NodeId, NodeProperty } from './LGraphNode'
import type { LLink, LinkId } from './LLink' import type { LLink, LinkId } from './LLink'
import type { Reroute, RerouteId } from './Reroute' import type { Reroute, RerouteId } from './Reroute'
import type { SubgraphInput } from './subgraph/SubgraphInput' import type { SubgraphInput } from './subgraph/SubgraphInput'
import type { SubgraphInputNode } from './subgraph/SubgraphInputNode' import type { SubgraphInputNode } from './subgraph/SubgraphInputNode'
import type { SubgraphOutputNode } from './subgraph/SubgraphOutputNode' import type { SubgraphOutputNode } from './subgraph/SubgraphOutputNode'
import type { LinkDirection, RenderShape } from './types/globalEnums' import type {
LGraphEventMode,
LinkDirection,
RenderShape
} from './types/globalEnums'
import type { IBaseWidget } from './types/widgets' import type { IBaseWidget } from './types/widgets'
export type Dictionary<T> = { [key: string]: T } export type Dictionary<T> = { [key: string]: T }
@@ -373,6 +377,22 @@ export interface INodeOutputSlot extends INodeSlot {
slot_index?: number slot_index?: number
} }
/** Options for {@link LiteGraphGlobal.createNode}. Shallow-copied onto the new node. */
export interface CreateNodeOptions {
pos?: Point
size?: Size
properties?: Dictionary<NodeProperty | undefined>
flags?: Partial<INodeFlags>
mode?: LGraphEventMode
color?: string
bgcolor?: string
boxcolor?: string
title?: string
shape?: RenderShape
inputs?: Partial<INodeInputSlot>[]
outputs?: Partial<INodeOutputSlot>[]
}
/** Links */ /** Links */
export interface ConnectingLink extends IInputOrOutput { export interface ConnectingLink extends IInputOrOutput {
node: LGraphNode node: LGraphNode

View File

@@ -91,6 +91,7 @@ export { RecursionError } from './infrastructure/RecursionError'
export type { export type {
CanvasColour, CanvasColour,
ColorOption, ColorOption,
CreateNodeOptions,
IContextMenuOptions, IContextMenuOptions,
IContextMenuValue, IContextMenuValue,
INodeInputSlot, INodeInputSlot,

View File

@@ -12,7 +12,7 @@ import { app } from '@/scripts/app'
import { useLitegraphService } from '@/services/litegraphService' import { useLitegraphService } from '@/services/litegraphService'
import { useModelToNodeStore } from '@/stores/modelToNodeStore' import { useModelToNodeStore } from '@/stores/modelToNodeStore'
interface CreateNodeOptions { interface ModelNodeCreateOptions {
position?: Point position?: Point
} }
@@ -48,7 +48,7 @@ type Result<T, E> = { success: true; value: T } | { success: false; error: E }
*/ */
export function createModelNodeFromAsset( export function createModelNodeFromAsset(
asset: AssetItem, asset: AssetItem,
options?: CreateNodeOptions options?: ModelNodeCreateOptions
): Result<LGraphNode, NodeCreationError> { ): Result<LGraphNode, NodeCreationError> {
const validatedAsset = assetItemSchema.safeParse(asset) const validatedAsset = assetItemSchema.safeParse(asset)

View File

@@ -22,6 +22,7 @@ import {
createBounds createBounds
} from '@/lib/litegraph/src/litegraph' } from '@/lib/litegraph/src/litegraph'
import type { import type {
CreateNodeOptions,
GraphAddOptions, GraphAddOptions,
IContextMenuValue, IContextMenuValue,
Point, Point,
@@ -885,7 +886,7 @@ export const useLitegraphService = () => {
function addNodeOnGraph( function addNodeOnGraph(
nodeDef: ComfyNodeDefV1 | ComfyNodeDefV2, nodeDef: ComfyNodeDefV1 | ComfyNodeDefV2,
options: Record<string, unknown> & { pos?: Point } = {}, options: CreateNodeOptions = {},
addOptions?: GraphAddOptions addOptions?: GraphAddOptions
): LGraphNode | null { ): LGraphNode | null {
options.pos ??= getCanvasCenter() options.pos ??= getCanvasCenter()