ChatGPT解决这个技术问题 Extra ChatGPT

“HTMLElement”类型的值上不存在属性“值”

我正在玩打字稿,并试图创建一个脚本,该脚本将在输入框中输入文本时更新 p 元素。

html 如下所示:

<html>
    <head>
    </head>
    <body>
        <p id="greet"></p>
        <form>
            <input id="name" type="text" name="name" value="" onkeyup="greet('name')" />
        </form>
    </body>
    <script src="greeter.js"></script>
</html>

greeter.ts 文件:

function greeter(person)
{
    return "Hello, " + person;
}

function greet(elementId)
{
    var inputValue = document.getElementById(elementId).value;

    if (inputValue.trim() == "")
        inputValue = "World";

    document.getElementById("greet").innerText = greeter(inputValue);
}

当我用 tsc 编译时,我得到以下“错误”:

/home/bjarkef/sandbox/greeter.ts(8,53): The property 'value' does not exist on value of type 'HTMLElement'

但是编译器确实输出了一个 javascript 文件,该文件在 chrome 中运行良好。

我怎么会收到这个错误?我该如何解决?

另外,我在哪里可以根据打字稿查找 'HTMLElement' 上哪些属性有效?

请注意,我对 javascript 和 typescript 非常陌生,所以我可能会遗漏一些明显的东西。 :)


K
Kayce Basques

根据 Tomasz Nurkiewiczs 的回答,“问题”是打字稿是类型安全的。 :) 所以 document.getElementById() 返回不包含 value 属性的类型 HTMLElement。然而,子类型 HTMLInputElement 确实包含 value 属性。

因此,一种解决方案是将 getElementById() 的结果转换为 HTMLInputElement,如下所示:

var inputValue = (<HTMLInputElement>document.getElementById(elementId)).value;

<> 是 typescript 中的强制转换运算符。请参阅问题 TypeScript: casting HTMLElement

如果您在 .tsx 文件中,上述转换语法将引发错误。您将希望改用此语法:

(document.getElementById(elementId) as HTMLInputElement).value

上面一行生成的 javascript 如下所示:

inputValue = (document.getElementById(elementId)).value;

即不包含类型信息。


您是否有任何列表 html 的哪个元素属于 typescript 的哪个类型?如果是,那么请发布它对某人有帮助!感谢您的出色回答。
这个修复完全破坏了我的代码;说接下来发生的任何事情“都不是功能”。我不明白 TS 处理这个问题的原因;由于 getElementById 可以返回任何元素类型,因此默认情况下应该接受任何元素。
@TurtlesAreCute 我很好奇这个解决方案是如何破坏你的代码的。希望一年后您找到了解决方案,但转换为 HTMLInputElement 应该可行。
就我而言,我不得不将其更改为 HTMLAnchorElement。
@Wildhammer 因为您的元素不是 Input 元素! OP是。
M
Michael

如果您正在使用 react,则可以使用 as 运算符。

let inputValue = (document.getElementById(elementId) as HTMLInputElement).value;

出于某种原因,这里接受的答案对我提出了以下错误:JSX 元素“HTMLInputElement”没有相应的结束标记。这是对我有用的答案。
原因是因为在 tsx 文件中,您不能使用 <> 运算符进行强制转换,因为它们在 React 中使用。所以你必须使用:basarat.gitbooks.io/typescript/docs/types/…
虽然这对我不起作用,但它确实指引了我正确的方向:) 投票!!!
我很确定 as 运算符是 TypeScript 注释,而不是 React。谢谢。
这对我很有效,因为我试图重置表单 (document.getElementById("addUserForm") as HTMLFormElement).reset();
L
Leo

我们可以assert

const inputElement: HTMLInputElement = document.getElementById('greet')

或使用 as-syntax

const inputElement = document.getElementById('greet') as HTMLInputElement

给予

const inputValue = inputElement.value // now inferred to be string

w
woodysan

尝试将要更新的元素转换为 HTMLInputElement。如其他答案所述,您需要向编译器提示这是一种特定类型的 HTMLElement:

var inputElement = <HTMLInputElement>document.getElementById('greet');
inputElement.value = greeter(inputValue);

i
inDream

对此的快速解决方法是使用 [ ] 选择属性。

function greet(elementId) {
    var inputValue = document.getElementById(elementId)["value"];
    if(inputValue.trim() == "") {
        inputValue = "World";
    }
    document.getElementById("greet").innerText = greeter(inputValue);
}

我只是尝试了几种方法并找出了这个解决方案,我不知道您原始脚本背后的问题是什么。

作为参考,您可以参考 Tomasz Nurkiewicz 的帖子。


正确回答这个问题,对我帮助很大。
T
Tomasz Nurkiewicz

问题在这里:

document.getElementById(elementId).value

您知道从 getElementById() 返回的 HTMLElement 实际上是从它继承的 HTMLInputElement 的一个实例,因为您传递的是输入元素的 ID。同样,在静态类型的 Java 中,这不会编译:

public Object foo() {
  return 42;
}

foo().signum();

signum()Integer 的一个方法,但编译器只知道 foo() 的静态类型,即 Object。并且 Object 没有 signum() 方法。

但是编译器不知道,它只能基于静态类型,而不是代码的动态行为。据编译器所知,document.getElementById(elementId) 表达式的类型没有 value 属性。只有输入元素才有价值。

对于 MDN 中的参考检查 HTMLElementHTMLInputElement。我猜 Typescript 或多或少与这些一致。


但我不是在 p 元素上访问 .value,而是在 input 元素上访问它。还是我弄错了?
@bjarkef:您正在调用 document.getElementById("greet") 并且您有 <p id="greet"></p>...
我正在调用 document.getElementById("greet").innerText,它应该是完全有效的,我只在包含以下行的输入元素上访问 value 属性:greet(elementId) 中的 var inputValue = document.getElementById(elementId).value; 并且在输入中的 html onkeyup="greet('name')" 中调用形式。所以我认为你误读了代码,如果我错了,请纠正我。 :)
@bjarkef:对不起,你是对的。我已经重写了我的答案,看看!
啊,这很有道理。那么我应该转换从 getElementById 返回的值吗?我该如何在打字稿中做到这一点?还是有除 getElementById 之外的另一种方法返回 HTMLInputElement
K
KidKode

同样对于使用 Props 或 Refs 等属性但没有您的“DocgetId”的任何人,您可以:

("" as HTMLInputElement).value;

倒引号是您的道具值,因此示例如下:

var val = (this.refs.newText as HTMLInputElement).value;
alert("Saving this:" + val);

e
emmaakachukwu

对于那些可能仍在为此苦苦挣扎的人,另一种选择是使用 (document.getElementById(elementId) as HTMLInputElement).value = ''source

如果您仍然遇到问题,请尝试将其提取到如下函数:

function myInput() {
   (document.getElementById(elementId) as HTMLInputElement).value = ''
}

C
CertainPerformance

有一种方法可以实现这种 没有 类型断言,通过使用 generics 来代替,通常使用起来更好更安全。

不幸的是,getElementById 不是通用的,但 querySelector 是:

const inputValue = document.querySelector<HTMLInputElement>('#greet')!.value;

同样,您可以使用 querySelectorAll 选择多个元素并使用泛型,以便 TS 可以了解所有选定的元素都是特定类型:

const inputs = document.querySelectorAll<HTMLInputElement>('.my-input');

这将产生一个 NodeListOf<HTMLInputElement>


我在 js 文件中的 Vscode 中收到错误,其中 checkJstsconfig 中为 true,并且目标:Es2020。使用 querySelector 并发送输入值时,到另一个网站的 fetch() 不起作用,而使用 getelementbyid 它可以工作。我该怎么办?
您可能没有使用正确的语法。如果您有 getElementById('foo') 并且有效,那么要转换为 querySelector,您需要 querySelector('#foo')#。然后使用 .querySelector<HTMLElement>('#foo') 添加泛型
R
Rohit Grover

如果您使用的是角度,您可以使用 -

const element = document.getElementById('elemId') as HTMLInputElement;

t
touchmarine
const a = document.getElementById("a")
if (a instanceof HTMLInputElement) {
    // a.value is valid here
    console.log(a.value)
}

更安全的方式

上面的代码片段是anwser的要点;继续阅读推理。

大多数现有答案都推荐使用 Type assertions(类型转换),它可以完成这项工作,但有点像使用 any - 它禁用类型检查。有一种更好、更安全的方法。

类型断言就像告诉 TypeScript 假装一个变量是我们所说的类型。因此,TypeScript 将为该类型执行类型检查。如果我们犯了错误并告诉它错误的类型,我们会得到一种错误的安全感,因为不会有编译警告,但在运行时会出现错误。让我们看一个例子:

// <input id="a" value="1">
// <div   id="b" value="2"></div>

const a = document.getElementById("a") as HTMLInputElement
const b = document.getElementById("b") as HTMLInputElement

console.log(a.value) // 1
console.log(b.value) // undefined

我们已经告诉 TypeScript,ab 是 HTMLInputElement 类型,它会这样对待它们。但是,由于 b 是没有 value 属性的 HTMLDivElement 类型,因此 b.value 返回 undefined

带有类型保护的类型缩小

更好的方法是使用允许更好控制的类型保护。

type guard 是一种在运行时确定变量类型的方法。虽然类型断言只是说:“变量 x 属于 T 类型”,但类型保护说:“如果变量 x 具有这些属性,则它属于 T 类型”。让我们快速看看类型保护的外观:

const a = document.getElementById("a")
if (a instanceof HTMLInputElement) {
    // a == input element
} else {
    // a != input element
}

这种类型保护只检查 a 是否是 HTMLInputElement 的实例。如果是,TypeScript 将识别它并将 if 块中的 a 视为该类型——它将允许访问输入元素的所有属性。这称为类型缩小。

为什么要使用类型保护而不是类型断言?出于同样的原因,您处理错误。虽然类型保护仍然不会在编译时输出警告,但它们让您可以控制。您(和 TypeScript)无法保证 value 属性是否存在,但通过类型断言,您可以决定在不存在的情况下该怎么做。 类型断言就像忽略错误,类型保护就像处理错误。

如何使用类型保护

我们将展示修复“属性不存在”错误的三种方法。每个示例都使用相同的 HTML,但它分别包含在每个示例中,因此更易于阅读。

类型断言

// <input id="a" value="1">
// <div   id="b" value="2">

const a = document.getElementById("a") as HTMLInputElement // correct type assertion
const b = document.getElementById("b") as HTMLInputElement // incorrect type assertion
const c = document.getElementById("c") as HTMLInputElement // element doesn't exist

console.log(a.value) // 1
console.log(b.value) // undefined
console.log(c.value) // Uncaught TypeError: Cannot read property 'value' of null

内联型防护装置

// <input id="a" value="1">
// <div   id="b" value="2">

const a = document.getElementById("a")
const b = document.getElementById("b")
const c = document.getElementById("c")

if (a instanceof HTMLInputElement) {
    console.log(a.value) // 1
}
if (b instanceof HTMLInputElement) {
    console.log(b.value)
}
if (c instanceof HTMLInputElement) {
    console.log(c.value)
}

bc 没有记录任何内容,因为它们不是输入元素。请注意,我们没有像“类型断言”示例中那样得到任何意外行为。

请注意,这是一个人为的示例,通常您会处理类型不是您预期的情况。如果类型不匹配,我经常抛出,如下所示:

if (!(b instanceof HTMLInputElement)) {
    throw new Error("b is not an input element")
}
// b == input element (for the rest of this block)

函数类型守卫

对于这个用例来说,这个例子更高级一点,也有点不必要。但是,它展示了函数类型保护和更“灵活”的类型保护。

函数类型保护是确定给定值是否属于某种类型的函数。他们通过简单地返回一个布尔值来做到这一点。为了使 TypeScript 能够理解您正在制作类型保护,您必须使用类型谓词(参见下面示例中的注释)。

// <input id="a" value="1">
// <div   id="b" value="2">

const a = document.getElementById("a")
const b = document.getElementById("b")
const c = document.getElementById("c")

if (hasValueProperty(a)) {
    console.log(a.value) // 1
}
if (hasValueProperty(b)) {
    console.log(b.value)
}
if (hasValueProperty(c)) {
    console.log(c.value)
}

const d = {
    "value": "d",
}
if (hasValueProperty(d)) {
    console.log(d.value) // d
}

type WithValue = {
    value: string
}

// hasValueProperty is a type guard function the determines whether x is of type
// WithValue.
//
// "x is WithValue" is a type predicate that tells TypeScript that this is a
// type guard.
function hasValueProperty(x: unknown): x is WithValue {
    return typeof x === "object" && x !== null && typeof (x as WithValue).value === "string"
}

请注意,由于我们的类型保护只检查“值”属性的存在,它也可以用于任何其他对象(不仅仅是元素)。


D
Dharman

这对我有用:

let inputValue = (swal.getPopup().querySelector('#inputValue ')as HTMLInputElement).value

需要格式化
另外,swal 是什么意思?
S
Stebenwolf

我遇到了类似的问题 (TS warning in JS file: "Property X does not exist on type X": is it possible to write cleaner JavaScript?)

虽然该标记有助于删除 typescript 文件中的警告,但编译后我的 JavaScript 文件中仍然会收到警告。

那么如何编写干净且允许我操作 .value 的代码呢?

我花了很长时间,但我通过使用另一种方法找到了解决方案:

HTML 代码:

<form id="my-form" 
   action="index.html"
   method="get"
   onsubmit="return showValue();">
    <input type="text" name="username">
    <input type="text" name="full-name">
    <input type="password" name="password">
    <button type="button" onclick="showValue();">Show value</button>
</form>

Javascript代码:

function showValue() {
    const myForm = document.forms.my-form;
    console.log(myForm?.username.value);
    return 1;
}

document.forms.x 有一个属性 "value",它会删除 typescript 文件和生成的 JavaScript 中的警告。


J
JaMondo

如果您有需要分配动态值的动态元素 ID,则可以使用:

//element_id = you dynamic id.
//dynamic_val = you dynamic value.
let _el = document.getElementById(element_id);
_el.value = dynamic_val.toString();

这对我有用。


j
jfunk

这可能看起来很陈词滥调,但这对我有用:

yarn add -D @types/web

我想我一定有一个过时的类型定义。


S
Stefano Zanini

问题:

错误“HTMLElement”类型上不存在属性“文本”

解决方案:在 typeScript 中,我们需要转换 document.getElementById(),它在 < HTMLScriptElement > 中返回类型 HTMLElement

所以我们可以通过以下方式来解决 typescript.js 预期的错误

Code: var content: string = ( < HTMLScriptElement > document.getElementById(contentId)).text;

它对我有用..希望它也对你有用。


我发现类型转换在处理 cypress return HTMLElement 时很有帮助