Mimicking JSX attributes behaviour with object types
OliverJAsh opened this issue ยท 7 comments
Search Terms
jsx object invalid data attribute nested component react
Suggestion
We have this behaviour for JSX:
Note: If an attribute name is not a valid JS identifier (like a data-* attribute), it is not considered to be an error if it is not found in the element attributes type.
https://www.typescriptlang.org/docs/handbook/jsx.html#attribute-type-checking
import React, { FC } from 'react';
const MyComponent: FC<{ myProp: string }> = props => null;
<MyComponent myProp="foo" data-test="foo" />;
I want this same behaviour but for object types. This is necessary for times when we want to pass some props as a nested object (for whatever reason). Currently this errors:
const MyComponent2: FC<{ props: { myProp: string } }> = props => null;
<MyComponent2 props={{ myProp: 'foo', 'data-test': 'foo' }} />;
As far as I'm aware, there's currently no way to extend the above props type to allow for this behaviour.
Checklist
My suggestion meets these guidelines:
- This wouldn't be a breaking change in existing TypeScript/JavaScript code
- This wouldn't change the runtime behavior of existing JavaScript code
- This could be implemented without emitting different JS based on the types of the expressions
- This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, etc.)
- This feature would agree with the rest of TypeScript's Design Goals.
It seems like this can be solved in TypeScript 4.4 with template literal types as object keys:
import * as React from 'react';
type DataAttributeKey = `data-${string}`;
interface HTMLAttributes extends React.HTMLAttributes<any> {
[dataAttribute: DataAttributeKey]: any;
}
function Component(props: { host: HTMLAttributes }) {
return <div {...props.host} />
}
<Component host={{
'data-testid': 'component',
'role': 'generic',
// @ts-expect-error
shouldError: 1
}} />
Possibly related: #47211
in vue3 typescript I am having some property does not exist in the HtmlElement error. please help me to solve this issue.
(property) dataButtons: string
(property) data-buttons: string
Type '{ class: string; dataButtons: string; "data-buttons": string; }' is not assignable to type 'HTMLAttributes'.
Property 'dataButtons' does not exist on type 'HTMLAttributes'.ts(2322)
Together with module augmentation it can be defined once in a global type definitions module, e.g. src/types/react.d.ts
:
import 'react';
declare module 'react' {
export interface HTMLAttributes<T> {
[dataAttribute: `data-${string}`]: any;
}
}
Not sure why this isn't supported in @types/react
already
Nobody proposed the change yet. It may not be trivial to do since adding properties may break existing typechecking. Somebody just needs to own this change.