[2.0 rc.15 / next] Types: `data-*` attributes are rejected in props objects typed with `ComponentProps` / `JSX.HTMLAttributes`
I maintainer di solito rispondono entro 1 giorno
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 3/5
- Tempo stimato
- Mezza giornata
- Idoneità per principianti
- 45/100
- Tipo di issue
- Bug
- Chiarezza
- Specificata chiaramente
- Stato di attività
- Attiva
- Stack tecnologico
- typescript
- Ambito
- frontend
Direzione di ricerca
Start with the JSX type declarations in packages/web (the DOM attribute interfaces and the ElementAttributes base), and reproduce with the three errors in the gist, using tsc -p .. The fix is a template-literal index signature for data-${string} keys on the base attribute interface. Done when the three errors disappear, the @ts-expect-error checks still fail for non-data keys and non-primitive data values, and the type tests pass. Because this touches public types, confirm the approach with a maintainer first.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Summary
In JSX, data-* attributes are accepted on intrinsic elements. In an object typed with the same element's props (ComponentProps<"div">, JSX.HTMLAttributes<T>), they are rejected. That type is the natural one for a function that returns props to spread onto an element. This request is to declare data-* keys in the DOM attribute types with a template-literal index signature.
Reproduction
import type { ComponentProps, JSX } from "@solidjs/web";
// In JSX, data-* attributes are accepted on intrinsic elements:
export const ok = <div data-state="open" />;
// ...but not in an object typed with the same element's props:
export const a: JSX.HTMLAttributes<HTMLDivElement> = { "data-state": "open" };
export const b: ComponentProps<"div"> = { role: "button", "data-state": "open" };
// ...nor when a function returning those props is spread back onto the element:
function disclosure(): ComponentProps<"button"> {
return { "aria-expanded": "false", "data-state": "closed" };
}
export const c = <button {...disclosure()} />;
tsc -p . (TypeScript 5.9.3 and 7.0.2 give the same errors) with "jsx": "preserve", "jsxImportSource": "@solidjs/web", "strict": true:
data-attrs.tsx(7,56): error TS2353: Object literal may only specify known properties, and '"data-state"' does not exist in type 'HTMLAttributes<HTMLDivElement>'.
data-attrs.tsx(8,59): error TS2353: Object literal may only specify known properties, and '"data-state"' does not exist in type 'HTMLAttributes<HTMLDivElement> & Properties<HTMLDivElement>'.
data-attrs.tsx(12,38): error TS2353: Object literal may only specify known properties, and '"data-state"' does not exist in type 'ButtonHTMLAttributes<HTMLButtonElement> & Properties<HTMLButtonElement>'.
TypeScript exempts hyphenated names from attribute checks only in JSX syntax, so the object forms fail.
Proposal
Add a template-literal index signature to the base attribute interface in @solidjs/web's JSX types. I tested this module augmentation against rc.15:
import "@solidjs/web";
declare module "@solidjs/web" {
namespace JSX {
interface ElementAttributes<T> {
[attr: `data-${string}`]: string | number | boolean | undefined;
}
}
}
With it, the three errors above go away, and these still hold:
type P = Omit<ComponentProps<"div">, "ref">;
export const p: P = { "data-x": "1", class: "a" };
// @ts-expect-error unknown non-data keys are still rejected
export const q: P = { foo: 1 };
// @ts-expect-error data values stay primitive
export const r: P = { "data-x": {} };
export const s = <div data-n={1} data-b={true} />;
React's DOM types have the same gap, so this is not a regression. Solid 2 is already rewriting the attribute types (lowercase names, RemoveAttribute), so this seems a good point to close it.
Why it matters
Headless component libraries expose state as data-* attributes (data-state, data-disabled, data-highlighted) and compose behaviour as functions that return props objects, which are merged and spread onto parts. Without the index signature, each such function has to widen its return type or cast. Until this lands, the augmentation above is the workaround.
Versions
@solidjs/web/solid-js2.0.0-rc.15. Onnextat eb4e019,packages/webdeclares nodata-*key.- TypeScript 5.9.3 and 7.0.2
Runnable repro: https://gist.github.com/cevr/e421f9dbfe6c0da2e92818647dd408f0 (bun install && bun run repro)
Filed with Claude Code on behalf of @cevr.
- Lingua principale
- TypeScript
- Stelle
- 36.1k
- Fork
- 1.1k
- Merge medio
- 11h 45m
- PR unite (30g)
- 329
Preparare l'ambiente
- Nessun Dockerfile né file Docker Compose
- Ha un modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di solidjs/solid
-
CHEATSHEET.md and RFC 02 still recommend module-scope state for app-wide state (follow-up to #3390)Aperta
Difficoltà 1/5 1-3 ore Idoneità per principianti 86/100
I maintainer di solito rispondono entro 1 giorno
-
`lazy()`: remounting an already-loaded component renders empty (or the Suspense fallback) since 1.9.14Forse già presa @itisrmk l’ha presa 1 giorno fa. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 62/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 4/5 1-2 giorni Idoneità per principianti 48/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 4/5 3-5 giorni Idoneità per principianti 48/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 4/5 3-5 giorni Idoneità per principianti 42/100
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di solidjs/solid
Issue simili
-
"Contains" page watch never matches when its text has a trailing spaceForse già presa @RaphaelFakhri l’ha presa oggi. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 77/100
CopilotKit/openmuse#184 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 88/100
I maintainer di solito rispondono entro 1 giorno
-
bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 67/100
bootstrap-vue-next/bootstrap-vue-next#3357 ·
I maintainer di solito rispondono entro 1 giorno
-
[quality] tide.ts: six mutation survivors in the merge-queue gate, draft refusal, fork-403 workflow-file diagnosis and getPull's fork flag are unpinned by any testForse già presa @hivecommons-hive l’ha presa oggi. Apertaagent/quality needs-kind stage/040-covered-by-pr testing
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
cncf/prow-github-actions#517 · 1 commento ·
I maintainer di solito rispondono entro 2 giorni
-
Unsampled pageload span is profiled when profileLifecycle is 'trace' (browser UI profiling)Forse già presa @Jxxunnn l’ha presa oggi. ApertaBrowser Waiting for: Product Owner
Difficoltà 2/5 1-3 ore Idoneità per principianti 82/100
getsentry/sentry-javascript#25497 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno