我对TypeScript是个新手,3天前才开始学习。当我在玩TypeScript(接口)的时候,我遇到了一个问题。当我尝试这样做的时候,它给了我一个错误:
const divEl:HTMLElement = document.createElement("div");
divEl.someRandomThing = "Some random thing!";
ERROR: error TS2339: Property 'someRandomThing' does not exist on type 'HTMLElement'.
如何向HTMLElement添加自定义属性(type)(此接口来自lib. dom. d. ts)?
我试过这个:
interface IMyInterface extends HTMLElement {
someRandomThing: string
}
const divEl:IMyInterface = document.createElement("div");
divEl.someRandomThing = "Some random thing!";
它给了我另一个错误:
ERROR: error TS2741: Property 'someRandomThing' is missing in type 'HTMLDivElement' but required in type 'IMyInterface'.
如果我在"someRandomThing"中添加一个问号,错误就会消失:
interface IMyInterface extends HTMLElement {
someRandomThing?: string //<-----
}
我总是要加一个问号吗?有没有一种方法,我不需要使用问号,而只是添加到HTMLElement的属性(类型)(这个接口是从lib.dom.d.ts)接口?
1条答案
按热度按时间nle07wnf1#
如何向HTMLElement添加自定义属性(type)(此接口来自lib. dom. d. ts)?
您的接口可以很好地完成这一任务,问题是您从
createElement
返回的内容没有新属性,因此无法满足新接口类型的要求,因此TypeScript会警告您这一点,因为这是TypeScript的主要任务。:-)当需要以这种方式扩展对象时,
Object.assign
是一种方便的一次性方法:Object.assign
的返回类型是其输入类型的交集,在本例中为HTMLElement & { someRandomThing: string; }
。对于可重用的对象,你可以写一个返回
IMyInterface
的新函数,在内部处理对象类型的变化,这个函数可以像上面那样使用Object.assign
,或者直接在内部使用一个小类型Assert来赋值给对象:as IMyInterface
是一个类型Assert,一般来说,避免类型Assert,但是在像这种实用函数这样的包含良好的上下文中,它们是可以的。如果需要的话,可以通过使该函数通用并提供属性名称和值来泛化该函数:
上面的Playground链接。
在上面的代码中,你可能已经注意到,在第一个内联版本中,元素的类型是
HTMLDivElement
(加上someRandomThing
),而不是jutHTMLElement
(加上someRandomThing
),但是其他版本中它只是HTMLElement
(加上someRandomThing
)。您可以通过使标记名也成为泛型来解决这个问题,从
createElement
中提升标记参数和返回类型的定义:其中,
divEl
的类型是HTMLDivElement & { someRandomThing: string; }
。Playground链接
附带说明:这与上面的类型相关方面基本上没有什么关系,但一般来说,就是向来自代码外部的对象(在本例中是DOM)添加自己的属性(这不是TypeScript的问题,只是编码的问题)。
1.从工程学的Angular 来看,它确实不是你要修改的对象,你不能确定这会对拥有该对象的代码产生什么影响。
1.可能会与页面上运行的其他代码(包括浏览器扩展)发生冲突。假设您的代码向元素添加了
marker
属性,而页面中的其他代码也对元素使用了自定义marker
属性?突然之间,您的代码和其他代码发生了交叉对话,可能会相互干扰。1.如果用足够多的代码或足够成功的库来完成,那么(在本例中)WHAT-WG就很难向DOM元素添加新的标准属性。在ES5中,JavaScript的数组有了一个新的标准方法
some
。它返回一个标志,表示数组中的any元素是否与您提供的 predicate 匹配。那么为什么它被称为"some"而不是"any"呢?因为有一个非常重要的库,它向数组添加了自己的方法any
,以及该库的编写方式,添加一个标准的会破坏使用该库的网站上的代码,所以我们坚持使用some
,它实际上没有什么意义,但却是最好的。在DOM的特定情况下,添加您自己的属性在所有现代浏览器上都能可靠地工作,而且这样做已有很长的历史(jQuery从v1开始就这样做了,尽管名称越来越晦涩)如果您选择这样做,请确保您使用的名称不太可能与现在或将来的任何名称冲突,或者更好的是,使用
Symbol
作为属性键。它保证是唯一的(如果您不通过Symbol.for
使其全局可访问)。无论何时,只要您想将自己的信息添加到来自代码外部的对象(并且不打算由代码"拥有"),至少可以执行两项操作,而不是将自己的属性添加到对象:
1.使用合成。例如:
现在,元素和
someRandomThing
被放在同一个容器中,当你需要someRandomThing
时,你可以使用something.someRandomThing
,当你需要元素时,你可以使用something.element
。1.使用由元素键控的
WeakMap
。例如:额外的信息在由实际元素示例键控的
WeakMap
中。当需要该元素时,使用element
。当需要它的信息时,使用elementInfo.get(element)?.someRandomThing
。如果在某个时候从DOM中删除了该元素,并且删除了对它的所有其他引用,则WeakMap
不会阻止该元素被垃圾收集。相反,则Map中针对它的条目消失。只是FWIW