From 1d2bc79cd26f10fb628ad8c2e10f6c66fc78e54f Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Wed, 13 May 2026 18:06:43 -0400 Subject: [PATCH] replace type arguments with a single one --- .../internal/client/custom-renderer/index.js | 13 +-- .../client/custom-renderer/types.d.ts | 67 +++++++------- packages/svelte/types/index.d.ts | 91 +++++++++---------- 3 files changed, 83 insertions(+), 88 deletions(-) diff --git a/packages/svelte/src/internal/client/custom-renderer/index.js b/packages/svelte/src/internal/client/custom-renderer/index.js index 8fc51d1f77..303fa82df8 100644 --- a/packages/svelte/src/internal/client/custom-renderer/index.js +++ b/packages/svelte/src/internal/client/custom-renderer/index.js @@ -1,5 +1,5 @@ /** @import { ComponentContext } from '#client' */ -/** @import { Renderer } from "./types.js" */ +/** @import { AnyNode, Renderer, RendererNodes } from "./types.js" */ /** @import { Component, ComponentType, SvelteComponent } from '../../../index.js' */ import { boundary } from '../dom/blocks/boundary.js'; import { branch, effect_root } from '../reactivity/effects.js'; @@ -8,12 +8,9 @@ import { push_renderer } from './state.js'; import { get_parent_node, remove_child } from '../dom/operations.js'; /** - * @template {object} [TFragment=object] - * @template {object} [TElement=object] - * @template {object} [TTextNode=object] - * @template {object} [TComment=object] - * @param {Renderer} renderer - * @returns {Renderer & { render: , Exports extends Record>(component: ComponentType> | Component, options: {} extends Props ? { target: TFragment | TElement | TTextNode | TComment, props?: Props, context?: Map } : { target: TFragment | TElement | TTextNode | TComment, props: Props, context?: Map }) => { component: Exports, unmount: () => void } }} + * @template {RendererNodes} T + * @param {Renderer} renderer + * @returns {Renderer & { render: , Exports extends Record>(component: ComponentType> | Component, options: {} extends Props ? { target: AnyNode, props?: Props, context?: Map } : { target: AnyNode, props: Props, context?: Map }) => { component: Exports, unmount: () => void } }} */ export function createRenderer(renderer) { const compound_renderer = { @@ -22,7 +19,7 @@ export function createRenderer(renderer) { * @template {Record} Props * @template {Record} Exports * @param {ComponentType> | Component} Component - * @param {{} extends Props ? { target: TFragment | TElement | TTextNode | TComment, props?: Props, context?: Map } : { target: TFragment | TElement | TTextNode | TComment, props: Props, context?: Map }} options + * @param {{} extends Props ? { target: AnyNode, props?: Props, context?: Map } : { target: AnyNode, props: Props, context?: Map }} options */ render(Component, { target, props, context }) { var pop_renderer = push_renderer(compound_renderer); diff --git a/packages/svelte/src/internal/client/custom-renderer/types.d.ts b/packages/svelte/src/internal/client/custom-renderer/types.d.ts index 81570b6b78..ffeb55705a 100644 --- a/packages/svelte/src/internal/client/custom-renderer/types.d.ts +++ b/packages/svelte/src/internal/client/custom-renderer/types.d.ts @@ -1,33 +1,32 @@ -export type NodeType = 'fragment' | 'element' | 'text' | 'comment'; - -export type Renderer< - TFragment extends object = object, - TElement extends object = object, - TTextNode extends object = object, - TComment extends object = object, - TNode extends TFragment | TElement | TTextNode | TComment = - | TFragment - | TElement - | TTextNode - | TComment -> = { +type NodeType = 'fragment' | 'element' | 'text' | 'comment'; + +export type RendererNodes< + Fragment extends object = object, + Element extends object = object, + TextNode extends object = object, + Comment extends object = object +> = { fragment: Fragment; element: Element; text: TextNode; comment: Comment }; + +type AnyNode = T[NodeType]; + +export type Renderer = { /** Creates a fragment, a container for multiple nodes. Inserting a fragment should insert all of its children. */ - createFragment(): TFragment; + createFragment(): T['fragment']; /** Creates an element with the given name. */ - createElement(name: string): TElement; + createElement(name: string): T['element']; /** Creates a text node with the given data. */ - createTextNode(data: string): TTextNode; + createTextNode(data: string): T['text']; /** * Creates a comment node with the given data. * This is often used as an anchor for inserting elements; it doesn't necessarily need to be rendered. */ - createComment(data: string): TComment; + createComment(data: string): T['comment']; /** Should return the type of the node in string form. */ - nodeType(node: TNode): NodeType; + nodeType(node: AnyNode): NodeType; /** * Return the value of the node: @@ -35,54 +34,54 @@ export type Renderer< * - data value of a comment * - null for elements and fragments */ - getNodeValue(node: TTextNode | TComment): string | null; + getNodeValue(node: T['text'] | T['comment']): string | null; /** Return the value of the attribute with the given name on the element, or null if it doesn't exist. */ - getAttribute(element: TElement, name: string): string | null; + getAttribute(element: T['element'], name: string): string | null; /** Set the attribute with the given name and value on the element. */ - setAttribute(element: TElement, key: string, value: any): void; + setAttribute(element: T['element'], key: string, value: any): void; /** Remove the attribute with the given name from the element. */ - removeAttribute(element: TElement, name: string): void; + removeAttribute(element: T['element'], name: string): void; /** Return true if the element has an attribute with the given name. */ - hasAttribute(element: TElement, name: string): boolean; + hasAttribute(element: T['element'], name: string): boolean; /** * Set the text content of the node to the given value. * This should work for both text nodes and elements. */ - setText(node: TElement | TTextNode | TComment, text: string): void; + setText(node: T['element'] | T['text'] | T['comment'], text: string): void; /** Return the first child of the element or fragment, or null if it has no children. */ - getFirstChild(element: TElement | TFragment): TNode | null; + getFirstChild(element: T['element'] | T['fragment']): AnyNode | null; /** Return the last child of the element or fragment, or null if it has no children. */ - getLastChild(element: TElement | TFragment): TNode | null; + getLastChild(element: T['element'] | T['fragment']): AnyNode | null; /** Return the next sibling of the node, or null if it has no next sibling. */ - getNextSibling(node: TElement | TTextNode | TComment): TNode | null; + getNextSibling(node: T['element'] | T['text'] | T['comment']): AnyNode | null; /** * Insert the element into the parent before the anchor. * If anchor is null, insert at the end. */ insert( - parent: TElement | TFragment, - element: TNode, - anchor: TElement | TTextNode | TComment | null + parent: T['element'] | T['fragment'], + element: AnyNode, + anchor: T['element'] | T['text'] | T['comment'] | null ): void; /** Remove the node from the tree. */ - remove(node: TElement | TTextNode | TComment): void; + remove(node: T['element'] | T['text'] | T['comment']): void; /** Return the parent of the element, or null if it has no parent. */ - getParent(element: TElement | TTextNode | TComment): TNode | null; + getParent(element: T['element'] | T['text'] | T['comment']): AnyNode | null; /** Add an event listener of the given type and handler to the target node. */ - addEventListener(target: TElement, type: string, handler: any, options?: any): void; + addEventListener(target: T['element'], type: string, handler: any, options?: any): void; /** Remove an event listener of the given type and handler from the target node. */ - removeEventListener(target: TElement, type: string, handler: any, options?: any): void; + removeEventListener(target: T['element'], type: string, handler: any, options?: any): void; }; diff --git a/packages/svelte/types/index.d.ts b/packages/svelte/types/index.d.ts index 9c2e2ba2b9..564ab7ec8f 100644 --- a/packages/svelte/types/index.d.ts +++ b/packages/svelte/types/index.d.ts @@ -2568,50 +2568,35 @@ declare module 'svelte/reactivity/window' { } declare module 'svelte/renderer' { - export function createRenderer(renderer: Renderer): Renderer & { - render: , Exports extends Record>(component: ComponentType> | Component, options: {} extends Props ? { - target: TFragment | TElement | TTextNode | TComment; - props?: Props; - context?: Map; - } : { - target: TFragment | TElement | TTextNode | TComment; - props: Props; - context?: Map; - }) => { - component: Exports; - unmount: () => void; - }; - }; type NodeType = 'fragment' | 'element' | 'text' | 'comment'; - type Renderer< - TFragment extends object = object, - TElement extends object = object, - TTextNode extends object = object, - TComment extends object = object, - TNode extends TFragment | TElement | TTextNode | TComment = - | TFragment - | TElement - | TTextNode - | TComment - > = { + type RendererNodes< + Fragment extends object = object, + Element extends object = object, + TextNode extends object = object, + Comment extends object = object + > = { fragment: Fragment; element: Element; text: TextNode; comment: Comment }; + + type AnyNode = T[NodeType]; + + export type Renderer = { /** Creates a fragment, a container for multiple nodes. Inserting a fragment should insert all of its children. */ - createFragment(): TFragment; + createFragment(): T['fragment']; /** Creates an element with the given name. */ - createElement(name: string): TElement; + createElement(name: string): T['element']; /** Creates a text node with the given data. */ - createTextNode(data: string): TTextNode; + createTextNode(data: string): T['text']; /** * Creates a comment node with the given data. * This is often used as an anchor for inserting elements; it doesn't necessarily need to be rendered. */ - createComment(data: string): TComment; + createComment(data: string): T['comment']; /** Should return the type of the node in string form. */ - nodeType(node: TNode): NodeType; + nodeType(node: AnyNode): NodeType; /** * Return the value of the node: @@ -2619,56 +2604,70 @@ declare module 'svelte/renderer' { * - data value of a comment * - null for elements and fragments */ - getNodeValue(node: TTextNode | TComment): string | null; + getNodeValue(node: T['text'] | T['comment']): string | null; /** Return the value of the attribute with the given name on the element, or null if it doesn't exist. */ - getAttribute(element: TElement, name: string): string | null; + getAttribute(element: T['element'], name: string): string | null; /** Set the attribute with the given name and value on the element. */ - setAttribute(element: TElement, key: string, value: any): void; + setAttribute(element: T['element'], key: string, value: any): void; /** Remove the attribute with the given name from the element. */ - removeAttribute(element: TElement, name: string): void; + removeAttribute(element: T['element'], name: string): void; /** Return true if the element has an attribute with the given name. */ - hasAttribute(element: TElement, name: string): boolean; + hasAttribute(element: T['element'], name: string): boolean; /** * Set the text content of the node to the given value. * This should work for both text nodes and elements. */ - setText(node: TElement | TTextNode | TComment, text: string): void; + setText(node: T['element'] | T['text'] | T['comment'], text: string): void; /** Return the first child of the element or fragment, or null if it has no children. */ - getFirstChild(element: TElement | TFragment): TNode | null; + getFirstChild(element: T['element'] | T['fragment']): AnyNode | null; /** Return the last child of the element or fragment, or null if it has no children. */ - getLastChild(element: TElement | TFragment): TNode | null; + getLastChild(element: T['element'] | T['fragment']): AnyNode | null; /** Return the next sibling of the node, or null if it has no next sibling. */ - getNextSibling(node: TElement | TTextNode | TComment): TNode | null; + getNextSibling(node: T['element'] | T['text'] | T['comment']): AnyNode | null; /** * Insert the element into the parent before the anchor. * If anchor is null, insert at the end. */ insert( - parent: TElement | TFragment, - element: TNode, - anchor: TElement | TTextNode | TComment | null + parent: T['element'] | T['fragment'], + element: AnyNode, + anchor: T['element'] | T['text'] | T['comment'] | null ): void; /** Remove the node from the tree. */ - remove(node: TElement | TTextNode | TComment): void; + remove(node: T['element'] | T['text'] | T['comment']): void; /** Return the parent of the element, or null if it has no parent. */ - getParent(element: TElement | TTextNode | TComment): TNode | null; + getParent(element: T['element'] | T['text'] | T['comment']): AnyNode | null; /** Add an event listener of the given type and handler to the target node. */ - addEventListener(target: TElement, type: string, handler: any, options?: any): void; + addEventListener(target: T['element'], type: string, handler: any, options?: any): void; /** Remove an event listener of the given type and handler from the target node. */ - removeEventListener(target: TElement, type: string, handler: any, options?: any): void; + removeEventListener(target: T['element'], type: string, handler: any, options?: any): void; + }; + export function createRenderer(renderer: Renderer): Renderer & { + render: , Exports extends Record>(component: ComponentType> | Component, options: {} extends Props ? { + target: TFragment | TElement | TTextNode | TComment; + props?: Props; + context?: Map; + } : { + target: TFragment | TElement | TTextNode | TComment; + props: Props; + context?: Map; + }) => { + component: Exports; + unmount: () => void; + }; }; /** * @deprecated In Svelte 4, components are classes. In Svelte 5, they are functions.