Bja*_*sen 204 typescript
我正在玩打字稿,我正在尝试创建一个脚本,在输入框中输入文本时将更新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>
Run Code Online (Sandbox Code Playgroud)
和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);
}
Run Code Online (Sandbox Code Playgroud)
当我编译时,tsc
我得到以下"错误":
/home/bjarkef/sandbox/greeter.ts(8,53): The property 'value' does not exist on value of type 'HTMLElement'
但是编译器确实输出了一个javascript文件,它在chrome中运行得很好.
我怎么会得到这个错误?我该如何解决?
另外,在哪里可以'HTMLElement'
根据打字稿查找哪些属性有效?
请注意我对javascript和打字稿很新,所以我可能会遗漏一些明显的东西.:)
Bja*_*sen 373
根据Tomasz Nurkiewicz的回答,"问题"是打字稿是类型安全的.:)所以document.getElementById()
返回HTMLElement
不包含value
属性的类型.HTMLInputElement
但是,子类型包含该value
属性.
因此,一个解决方案是投的结果getElementById()
,以HTMLInputElement
这样的:
var inputValue = (<HTMLInputElement>document.getElementById(elementId)).value;
Run Code Online (Sandbox Code Playgroud)
<>
是打字稿中的铸造操作符.请参阅问题TypeScript:cast HTMLElement.
上面的行中生成的javascript如下所示:
inputValue = (document.getElementById(elementId)).value;
Run Code Online (Sandbox Code Playgroud)
即不包含类型信息.
Mic*_*ael 47
如果您正在使用反应,您可以使用as
操作员.
let inputValue = (document.getElementById(elementId) as HTMLInputElement).value;
Run Code Online (Sandbox Code Playgroud)
woo*_*san 38
尝试将要更新的元素强制转换为HTMLInputElement.如其他答案中所述,您需要向编译器提示这是特定类型的HTMLElement:
var inputElement = <HTMLInputElement>document.getElementById('greet');
inputElement.value = greeter(inputValue);
Run Code Online (Sandbox Code Playgroud)
Leo*_*Leo 16
更新的示例:
const inputElement: HTMLInputElement = document.getElementById('greet') as HTMLInputElement
const inputValue: string = InputElement.value
Run Code Online (Sandbox Code Playgroud)
说明文件:
Tom*_*icz 15
问题出在这里:
document.getElementById(elementId).value
Run Code Online (Sandbox Code Playgroud)
你知道HTMLElement
返回getElementById()
的实际上是一个HTMLInputElement
继承它的实例,因为你传递了一个输入元素的ID.类似地,在静态类型的Java中,这将无法编译:
public Object foo() {
return 42;
}
foo().signum();
Run Code Online (Sandbox Code Playgroud)
signum()
是一种方法Integer
,但编译器只知道静态类型foo()
,即Object
.并Object
没有signum()
方法.
但编译器无法知道,它只能基于静态类型,而不能基于代码的动态行为.就编译器所知,document.getElementById(elementId)
表达式的类型没有value
属性.只有输入元素才有价值.
用于参考检查HTMLElement
和HTMLInputElement
MDN.我认为Typescript或多或少与这些一致.
inD*_*eam 14
对此的快速解决方法是使用[]选择属性.
function greet(elementId) {
var inputValue = document.getElementById(elementId)["value"];
if(inputValue.trim() == "") {
inputValue = "World";
}
document.getElementById("greet").innerText = greeter(inputValue);
}
Run Code Online (Sandbox Code Playgroud)
我只是尝试了几种方法并找到了这个解决方案,
我不知道原始脚本背后的问题是什么.
作为参考,您可以参考Tomasz Nurkiewicz的帖子.
tou*_*ine 12
const a = document.getElementById("a")\nif (a instanceof HTMLInputElement) {\n // a.value is valid here\n console.log(a.value)\n}\n
Run Code Online (Sandbox Code Playgroud)\n上面的代码片段是 anwser 的要点;继续阅读以了解推理。
\n大多数现有答案建议使用类型断言(类型转换)来完成这项工作,但有点像使用any
\xe2\x80\x94 来禁用类型检查。有更好、更安全的方法。
类型断言就像告诉 TypeScript 假装变量属于我们所说的类型。因此,TypeScript 将为该类型执行类型检查。如果我们犯了一个错误并告诉它错误的类型,我们就会产生一种错误的安全感,因为不会有编译警告,但在运行时会出现错误。让我们看一个例子:
\n// <input id="a" value="1">\n// <div id="b" value="2"></div>\n\nconst a = document.getElementById("a") as HTMLInputElement\nconst b = document.getElementById("b") as HTMLInputElement\n\nconsole.log(a.value) // 1\nconsole.log(b.value) // undefined\n
Run Code Online (Sandbox Code Playgroud)\n我们已经告诉 TypeScripta
和b
是 HTMLInputElement 类型,并且它会这样对待它们。但是,由于b
HTMLDivElement 类型没有该value
属性,b.value
因此返回undefined
。
更好的方法是使用类型保护,它可以进行更好的控制。
\n类型保护是一种在运行时确定变量类型的方法。类型断言只是说:“变量 x 属于 T 类型”,而类型防护则说:“如果变量 x 具有这些属性,则它属于 T 类型”。让我们快速看看类型保护的外观:
\nconst a = document.getElementById("a")\nif (a instanceof HTMLInputElement) {\n // a == input element\n} else {\n // a != input element\n}\n
Run Code Online (Sandbox Code Playgroud)\n此类型防护仅检查是否a
是 HTMLInputElement 的实例。如果是,TypeScript 将识别该类型并将a
if 块内部视为该类型\xe2\x80\x94,它将允许访问输入元素的所有属性。这称为类型缩小。
为什么应该使用类型保护而不是类型断言?出于同样的原因,您处理错误。虽然类型保护在编译时仍然不会输出警告,但它们让您可以控制。您(和 TypeScript)无法保证该value
属性是否存在,但通过类型断言,您可以决定在不存在的情况下该怎么做。类型断言就像忽略错误,类型防护就像处理错误。
我们将展示修复“该属性不存在”错误的三种方法。每个示例都使用相同的 HTML,但它单独包含在每个示例中,因此更易于阅读。
\n// <input id="a" value="1">\n// <div id="b" value="2">\n\nconst a = document.getElementById("a") as HTMLInputElement // correct type assertion\nconst b = document.getElementById("b") as HTMLInputElement // incorrect type assertion\nconst c = document.getElementById("c") as HTMLInputElement // element doesn\'t exist\n\nconsole.log(a.value) // 1\nconsole.log(b.value) // undefined\nconsole.log(c.value) // Uncaught TypeError: Cannot read property \'value\' of null\n
Run Code Online (Sandbox Code Playgroud)\n// <input id="a" value="1">\n// <div id="b" value="2">\n\nconst a = document.getElementById("a")\nconst b = document.getElementById("b")\nconst c = document.getElementById("c")\n\nif (a instanceof HTMLInputElement) {\n console.log(a.value) // 1\n}\nif (b instanceof HTMLInputElement) {\n console.log(b.value)\n}\nif (c instanceof HTMLInputElement) {\n console.log(c.value)\n}\n
Run Code Online (Sandbox Code Playgroud)\nb
并且c
没有记录任何内容,因为它们不是输入元素。请注意,我们没有像“类型断言”示例中那样得到任何意外行为。
请注意,这是一个人为的示例,通常您会处理类型不是您期望的类型的情况。如果类型不匹配,我经常抛出错误,如下所示:
\nif (!(b instanceof HTMLInputElement)) {\n throw new Error("b is not an input element")\n}\n// b == input element (for the rest of this block)\n
Run Code Online (Sandbox Code Playgroud)\n这个例子有点高级,对于这个用例来说有点不必要。然而,它展示了功能类型防护和更“灵活”的类型防护。
\n函数类型保护是确定给定值是否属于某种类型的函数。他们通过简单地返回一个布尔值来做到这一点。为了让 TypeScript 能够理解您正在创建类型保护,您必须使用类型谓词(请参阅下面示例中的注释)。
\n// <input id="a" value="1">\n// <div id="b" value="2">\n\nconst a = document.getElementById("a")\nconst b = document.getElementById("b")\nconst c = document.getElementById("c")\n\nif (hasValueProperty(a)) {\n console.log(a.value) // 1\n}\nif (hasValueProperty(b)) {\n console.log(b.value)\n}\nif (hasValueProperty(c)) {\n console.log(c.value)\n}\n\nconst d = {\n "value": "d",\n}\nif (hasValueProperty(d)) {\n console.log(d.value) // d\n}\n\ntype WithValue = {\n value: string\n}\n\n// hasValueProperty is a type guard function the determines whether x is of type\n// WithValue.\n//\n// "x is WithValue" is a type predicate that tells TypeScript that this is a\n// type guard.\nfunction hasValueProperty(x: unknown): x is WithValue {\n return typeof x === "object" && x !== null && typeof (x as WithValue).value === "string"\n}\n
Run Code Online (Sandbox Code Playgroud)\n请注意,由于我们的类型保护仅检查“value”属性是否存在,因此它也可以用于任何其他对象(不仅仅是元素)。
\nKid*_*ode 11
对于使用Props或Refs等属性而没有"DocgetId"的人,您可以:
("" as HTMLInputElement).value;
Run Code Online (Sandbox Code Playgroud)
倒置引号是你的道具值,所以一个例子就是这样:
var val = (this.refs.newText as HTMLInputElement).value;
alert("Saving this:" + val);
Run Code Online (Sandbox Code Playgroud)
对于那些可能仍在为此苦苦挣扎的人,另一种选择是使用(document.getElementById(elementId) as HTMLInputElement).value = ''
. 来源。
如果您仍然遇到问题,请尝试将其提取为如下函数:
function myInput() { (document.getElementById(elementId) as HTMLInputElement).value = '' }
Run Code Online (Sandbox Code Playgroud)
小智 6
如果您使用的是角度,则可以使用 -
const element = document.getElementById('elemId') as HTMLInputElement;
Run Code Online (Sandbox Code Playgroud)
有一种方法可以在没有类型断言的情况下实现这一点,通过使用泛型来代替,通常使用起来更好更安全。
不幸的是,getElementById
它不是通用的,而是querySelector
:
const inputValue = document.querySelector<HTMLInputElement>('#greet')!.value;
Run Code Online (Sandbox Code Playgroud)
类似地,您可以使用querySelectorAll
来选择多个元素并使用泛型,以便 TS 可以理解所有选定的元素都属于特定类型:
const inputs = document.querySelectorAll<HTMLInputElement>('.my-input');
Run Code Online (Sandbox Code Playgroud)
这将产生一个NodeListOf<HTMLInputElement>
.
归档时间: |
|
查看次数: |
176004 次 |
最近记录: |