[英]Why can't the return type of document.createElement be assigned to a generic that's restricted to HTMLElement?
I'm writing a clone(el)
function that must accept an HTMLElement
or subtype, and should return the exact same type that it's given.我正在编写一个clone(el)
function,它必须接受HTMLElement
或子类型,并且应该返回与给定的类型完全相同的类型。
How can I write this function's generic signature to be correct please?我怎样才能写出这个函数的通用签名是正确的? Thanks!谢谢!
Is no.2 where I'm going wrong, in how T
is being restricted to HTMLElement
? 2 号是我哪里出错了, T
是如何被限制为HTMLElement
的?
To be precise, I'm writing plain JavaScript and using JSDoc in VS Code, which offers a @template
definition to define a generic :准确地说,我正在编写普通的 JavaScript 并在 VS Code 中使用 JSDoc,它提供了一个@template
定义来定义一个通用的:
T
定义一个泛型T
T
to HTMLElement
or subtypes thereof将T
限制为HTMLElement
或其子类型T
将第一个参数和返回类型都定义为泛型T
document.createElement(tagName: string)
which returns type HTMLElement
使用返回类型HTMLElement
的document.createElement(tagName: string)
createElement
is type T
– I, the author, know it will be, because creating an element with the same tagName will always result in the same type of element, but createElement
doesn't know this because it doesn't know specifically what value el.tagName
is, it only knows it's of type string
.确保createElement
的返回类型是T
类型——我,作者,知道它会是,因为创建一个具有相同标签名称的元素总是会产生相同类型的元素,但createElement
不知道这一点,因为它不知道不知道el.tagName
的具体值是什么,它只知道它的类型是string
。/**
* @template {HTMLElement} T
* @param {T} el
* @returns {T}
*/
function clone(el) {
/** @type {T} */
const newEl = document.createElement(el.tagName);
// ^^^^^ Error from above appears on this
// do copying of attributes and child nodes
return newEl;
}
I believe this to be the same result in TypeScript:我相信这与 TypeScript 中的结果相同:
function clone<T extends HTMLElement>(el: T): T {
const newEl: T = document.createElement(el.tagName);
// do copying of attributes and child nodes
return newEl;
}
View on TypeScript Playground 查看 TypeScript 游乐场
However, TypeScript complains that但是,TypeScript 抱怨说
Type 'HTMLElement' is not assignable to type 'T'.类型“HTMLElement”不可分配给类型“T”。
'HTMLElement' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'HTMLElement'. “HTMLElement”可分配给类型“T”的约束,但“T”可以用约束“HTMLElement”的不同子类型实例化。 (2322) (2322)
The error makes sense to me, because if I rewrite it for a specific example, I get the same error, but more understandable:这个错误对我来说很有意义,因为如果我为一个特定的例子重写它,我会得到同样的错误,但更容易理解:
function clone<T extends HTMLElement>(el: T): T {
return document.createElement('input');
}
View in TypeScript Playground 在 TypeScript 游乐场查看
Type 'HTMLInputElement' is not assignable to type 'T'.类型“HTMLInputElement”不可分配给类型“T”。
'HTMLInputElement' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'HTMLElement'. “HTMLInputElement”可分配给类型“T”的约束,但“T”可以用约束“HTMLElement”的不同子类型实例化。 (2322) (2322)
I've tried to read the answer in https://stackoverflow.com/a/59363875 but I feel like, in my case, I'm more restricted because document.createElement
is defining its type signature as Document.createElement(tagName: string, options?: ElementCreationOptions | undefined): HTMLElement
.我试图阅读https://stackoverflow.com/a/59363875中的答案,但我觉得,就我而言,我受到更多限制,因为document.createElement
将其类型签名定义为Document.createElement(tagName: string, options?: ElementCreationOptions | undefined): HTMLElement
。
The issue you're experiencing is because document.createElement returns an HTMLElement, which is a supertype of the type parameter T. This means that the return is not guaranteed to have the same type as el, and therefore you get a type error when trying to assign it to a variable of type T.您遇到的问题是因为 document.createElement 返回一个 HTMLElement,它是类型参数 T 的超类型。这意味着不能保证返回的类型与 el 相同,因此您在尝试时会遇到类型错误将其分配给类型 T 的变量。
Your final function is fairly close, you just need to make the return as type T.您的最终 function 非常接近,您只需要将返回作为类型 T。
function clone<T extends HTMLElement>(el: T): T {
const newEl = document.createElement(el.tagName);
return newEl as T;
}
or more succinctly或更简洁
function clone<T extends HTMLElement>(el: T): T {
return document.createElement(el.tagName) as T;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.