Definitelytyped: Typing for custom or unknown HTML element attributes is incorrect

Created on 12 Jun 2018  路  8Comments  路  Source: DefinitelyTyped/DefinitelyTyped

If you know how to fix the issue, make a pull request instead.

  • [x] I tried using the @types/xxxx package and had problems.
  • [x] I tried using the latest stable version of tsc. https://www.npmjs.com/package/typescript
  • [x] I have a question that is inappropriate for StackOverflow. (Please ask any appropriate questions there).
  • [x] [Mention](https://github.com/blog/821-mention-somebody-they-re-notified) the authors (see Definitions by: in index.d.ts) so they can respond.

    • Authors: @sheetalkamat @RyanCavanaugh @johnnyreilly @mhegazy

Problem

I'm using a <webview> builtin element in Electron, and the Typing for the element is opposite of what React expects at runtime. So if I adhere to what the type def dictates, then React throws a runtime error. If I change it to be what React wants at runtime, then TypeScript throws an error at build time.

This is the markup that React expects:

            return <webview
                src={ Path.join( 'file://', htmlEntry ) }
                nodeintegration="true"
            ></webview>

However TypeScript complains that nodeintegration should be a boolean:

          TS2322: Type '{ id: string; ref: (webview: any) => void; src: string; nodeintegration: string; allowpopups: str...' is not assignable to type 'DetailedHTMLProps<WebViewHTMLAttributes<HTMLWebViewElement>, HTMLWebViewElement>'.
      Type '{ id: string; ref: (webview: any) => void; src: string; nodeintegration: string; allowpopups: str...' is not assignable to type 'WebViewHTMLAttributes<HTMLWebViewElement>'.
        Types of property 'allowpopups' are incompatible.
          Type 'string' is not assignable to type 'boolean'.

If I change it so that TypeScript is happy, it looks like this:

            return <webview
                src={ Path.join( 'file://', htmlEntry ) }
                nodeintegration={true}
            ></webview>

Now I can successfully build without a TS error, but at runtime React will say this:

Warning: Received `true` for a non-boolean attribute `nodeintegration`.

If you want to write it to the DOM, pass a string instead: nodeintegration="true" or nodeintegration={value.toString()}.
    in webview (created by WebviewComponent)
    in ...

The DefinitelyTyped definition is located here:

https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react/global.d.ts#L123

How can I fix this?

workarounds

  1. One workaround is to escape from React and use DOM APIs to create/destroy the <webview> element in my React component's lifecycle methods.
  2. ~An easier workaround is to find some way to trick the system. In this case, the following use of toString() produces no type errors or React runtime errors (thanks to the suggestion in the React error, but it is weird):~ EDIT: I was wrong, this second workaround doesn't work.
    jsx return <webview src={ Path.join( 'file://', htmlEntry ) } nodeintegration={(true).toString()} ></webview>

Most helpful comment

@trusktr @thecorsair As nodeintegration of WebViewHTMLAttributes is already defined in index.d.ts and subsequent properties must be the same types, technically you can not solve it by merging declarations.

But you may try this

const trueAsStr = 'true' as any
(<webview nodeintegration={trueAsStr}>123</webview>)

I've never written eletron with react, but It makes senses to me.

All 8 comments

It'd be great if it was as simple as

            return <webview
                src={ Path.join( 'file://', htmlEntry ) }
                nodeintegration
            ></webview>

so it just works (like it does in Vue 馃槉).

I went with workaround 3, which works so far (I haven't tested what happens when the component re-renders):

        render() {

            return <div ref={ this.getWebview }
                dangerouslySetInnerHTML={ { __html: `
                    <webview
                        src="${ Path.join( 'file://', htmlEntry ) }"
                        nodeintegration
                    ></webview>
                ` } }
            ></div>

        }

As I suspected, it fails miserably on re-render. So option 3 isn't much of a workaround.

How can I override the HTMLWebViewElement type to add what I need?

same issue~~~~

@trusktr @thecorsair As nodeintegration of WebViewHTMLAttributes is already defined in index.d.ts and subsequent properties must be the same types, technically you can not solve it by merging declarations.

But you may try this

const trueAsStr = 'true' as any
(<webview nodeintegration={trueAsStr}>123</webview>)

I've never written eletron with react, but It makes senses to me.

@somarlyonks you're a lifesaver! That works. Not sure why I didn't try that!

If I understand correctly, the problem is that React's JSX compiler assumes that any attribute that it doesn't understand is a string attribute, and cannot convert into it from boolean.

If that's the case, I think DefinitelyTyped shouldn't annotate those attributes as boolean. Instead, the attributes should probably have HTML-style boolean definition:

interface WebViewHTMLAttributes<T> extends HTMLAttributes<T> {
    allowpopups?: "" | "allowpopups";
    nodeintegration?: "" | "nodeintegration";
    // etc.
}

Ugly, but what can we do.

Was this page helpful?
0 / 5 - 0 ratings