如何从库中向React的HTMLAttributes添加自定义属性?

时间:2018-12-24 16:24:00

标签: reactjs typescript typescript-typings

假设我正在构建一个可重用的库以用于React应用程序。该库将查找具有某些属性和值的某些DOM元素。

例如,它将查找具有“ foo”属性且可以等于“ bar”或“ baz”的DIV。

该库及其使用者均使用Typescript编写。

现在,当我尝试在用户代码中实例化DIV元素时:

// consumer/Consumer.tsx

import * as React from 'react';
import 'library';

export const Consumer = () =>
  <div foo="bar">Hello</div>;

我收到类型错误

Type '{ children: string; type: string; onClick: () => void; foo: string; }' is not assignable to type 'DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>'. Property 'foo' does not exist on type 'DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>'.ts(2322) (property) JSX.IntrinsicElements.button: React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>

我可以通过在消费者的代码中添加merged a module declaration and interface declaration来解决此问题:

// consumer/Consumer.tsx

import * as React from 'react';
import 'library';

declare module 'react' {
  interface HTMLAttributes<T> {
    readonly foo?: 'bar' | 'baz';
  }
}

export const Consumer = () =>
  <div foo="bar">Hello</div>;

但是,我认为这确实应该在我的库的代码中完成,而不是在消费者的代码中完成。毕竟,定义合同是图书馆的工作,而不是消费者的工作。使用者应该能够导入库从库定义的任何接口。

因此,我尝试将声明移到我的库代码中。我不确定在哪里放置它,所以我决定将它附加到index.ts文件中,该文件将导出库的所有组件:

// library/src/index.ts

export * from './LibraryComponent1.tsx';
export * from './LibraryComponent2.tsx';

// added declaration here:
declare module 'react' {
  interface HTMLAttributes<T> {
    readonly foo?: 'bar' | 'baz';
  }
}

不幸的是,这不起作用。当我重新编译该库并将其重新链接到我的使用者时,出现与上述相同的类型错误。

我尝试过:

  • 使用declare namespace代替declare module
  • 在库中export前面添加interface HTMLAttributes
  • 将声明放入另一个文件中
    • types / index.d.ts
    • src / types.d.ts
    • src / index.d.ts
    • src / test.ts
  • 以各种方式导入图书馆
    • 导入“库”;
    • 导入“ library / src”;
    • 导入“ library / src / types”;
    • 导入“库/类型”;
    • 从“库”中导入{HTMLAttributes};

我在这里想念什么?有什么想法吗?

2 个答案:

答案 0 :(得分:1)

首先,我本人不是TypeScript用户(尽管我在使用第三方软件包时已经对其进行了一些处理),因此,如果这个答案背叛了我对此领域的一些无知,我深表歉意。 / p>

您似乎想对图书馆承担不适当的责任。对我来说,您的库应该能够说出from django.contrib.auth.hashers import pbkdf2 import hashlib from base64 import b64decode identity_PasswordHash = "AOOVvPns8Nov6CsJDTAWz+QDOEO2csh60m5aYyX2Vn7LsNDhiiZ5UaSDWr5izwWeHA==" pwd_plain = 'Hellow123'; def dotnet_identity_check_password(password, hash): binsalt = b64decode(hash)[1:17] binpwd = b64decode(hash)[17:] genpwd = pbkdf2(password, binsalt, 1000, digest=hashlib.sha1, dklen=32) if genpwd == binpwd: return True return False if dotnet_identity_check_password(pwd_plain,identity_PasswordHash): print("OK") else: print("Fail") 是该库的组件之一中div的有效属性,但是您似乎在暗示该库应该能够具有以下优点:更改不是由库的组件产生的元素的有效性的效果。

为确保区分清楚。对于我来说,该库看起来像是自然的(假设将应用适当的TypeScript来使其有效):

foo

,然后允许消费者毫无问题地使用// library code export const LibComponent1 = (props) => { return <div foo="bar">{props.children}</div> } 。但是,允许更改库外部定义的组件中所有div的TypeScript验证以允许属性“ foo”似乎是不好的库行为。如果多个库执行此类操作,它们很容易彼此冲突或将问题隐藏在其他代码中。

答案 1 :(得分:-1)

假设您要在自定义组件中接受额外的属性,并使用传播运算符(例如...rest)作为预先存在的属性。这是您的操作方式:

interface Props{
  icon?: string; 
}

type Button = Props & React.HTMLProps<HTMLButtonElement> & React.HTMLAttributes<HTMLButtonElement>;

function Button({ 
  icon,
  ...rest
}: Button) {
  return (
    <button 
      {...rest}
    >
     {icon && <span>{icon}</span>}
     {children}       
    </button>
}