Search code examples
typescriptjsx

Define types for JSX: Property 'key' does not exist on type


I'm implementing an application customizing the jsxFactory function. So, my tsconfig.json is the following:

{
    "compilerOptions": {
        "lib": ["es2015", "dom"],
        "jsx": "react",
        "jsxFactory": "createDOMElement"
    },
    "include": ["./src/**/*"]
}

where createDOMElement is my custom function invoked for every JSX element.

My application code is the following:

function createDOMElement(tagName: string | Function, props: any, ...children: any[]) {
    /* my custom implementation */
}

function Button(data: { text: string }) {
    const button = (
        <button>{data.text}</button>
    );
    /* some logic here */
}

export function Main() {
    const el = (
        <Button text="the text" key="my-key"  />
    );

    /* some logic here */
}

As you can see, I defined two components:

  • Button is a component that accepts a string text as a property
  • Main is a component that creates the Button component, giving text and key properties.

While the text property is defined by Button signature, key isn't. Conceptually, key shouldn't be allowed for the component Button. In fact, VSCode gives me an error:

Type '{ key: string; text: string; }' is not assignable to type '{ text: string; }'.
  Property 'key' does not exist on type '{ text: string; }'.ts(2322)

Anyway, some libraries like react allow the specification of the key property even if the component doesn't have it as a property, and I want to do the same for my custom implementation of jsxFactory.

If I understood correctly, this is a typescript type problem, and the JSX typescript namespace allows me to define it, but I didn't understand how to let the key property for every component. I want to instantiate components specifying the defined properties and the key property, even if it is not specified.

How can I configure typescript to support it?


Solution

  • To support key attribute, you should extend IntrinsicAttributes interface as follows:

    
    declare global {
        namespace JSX {
            interface IntrinsicAttributes {
                key?: string
            }
        }
    }