我要将ASP.NET WebForms的Focus.js
(嵌入在System.Web.dll
中)转换为TypeScript(因为我正在维护一个WebForms项目,该项目大量使用了ASP.NET WebForms的库存)客户端脚本)。
这是WebForm_IsInVisibleContainer
中的原始JavaScript函数Focus.js
:
function WebForm_IsInVisibleContainer(ctrl) {
var current = ctrl;
while((typeof(current) != "undefined") && (current != null)) {
if (current.disabled ||
( typeof(current.style) != "undefined" &&
( ( typeof(current.style.display) != "undefined" &&
current.style.display == "none") ||
( typeof(current.style.visibility) != "undefined" &&
current.style.visibility == "hidden") ) ) ) {
return false;
}
if (typeof(current.parentNode) != "undefined" &&
current.parentNode != null &&
current.parentNode != current &&
current.parentNode.tagName.toLowerCase() != "body") {
current = current.parentNode;
}
else {
return true;
}
}
return true;
}
我已将其注释到此TypeScript中:
function WebForm_IsInVisibleContainer( ctrl: HTMLElement ): boolean {
var current = ctrl;
while( ( typeof ( current ) != "undefined" ) && ( current != null ) ) {
if( current.disabled ||
( typeof ( current.style ) != "undefined" &&
( ( typeof ( current.style.display ) != "undefined" &&
current.style.display == "none" ) ||
( typeof ( current.style.visibility ) != "undefined" &&
current.style.visibility == "hidden" ) ) ) ) {
return false;
}
if( typeof ( current.parentNode ) != "undefined" &&
current.parentNode != null &&
current.parentNode != current &&
(current.parentNode as HTMLElement).tagName.toLowerCase() != "body" ) {
current = current.parentNode;
}
else {
return true;
}
}
return true;
}
但是tsc
有两个编译器错误:
我的快速解决方案是添加这些类型断言(如下所示),但是感觉就像我做错了什么。尤其是因为ctrl
可以是HTMLSelectElement
或HTMLTextAreaElement
,而它们不是HTMLInputElement
但具有disabled: boolean
属性:
function WebForm_IsInVisibleContainer( ctrl: HTMLElement ): boolean {
var current = ctrl;
while( ( typeof ( current ) != "undefined" ) && ( current != null ) ) {
if( ( current as HTMLInputElement ).disabled || // <-- here
( typeof ( current.style ) != "undefined" &&
( ( typeof ( current.style.display ) != "undefined" &&
current.style.display == "none" ) ||
( typeof ( current.style.visibility ) != "undefined" &&
current.style.visibility == "hidden" ) ) ) ) {
return false;
}
if( typeof ( current.parentNode ) != "undefined" &&
current.parentNode != null &&
current.parentNode != current &&
(current.parentNode as HTMLElement).tagName.toLowerCase() != "body" ) {
current = current.parentNode as HTMLElement; // <-- and here
}
else {
return true;
}
}
return true;
}
在JavaScript中,最好使用if( current.disabled )
检查属性的存在-为什么TypeScript不支持此功能?
我知道另一种解决方法是像这样添加新界面:
interface DisableableHTMLElement extends HTMLElement {
disabled: boolean;
}
function WebForm_IsInVisibleContainer( ctrl: DisableableHTMLElement ): boolean {
// etc
}
...但这感觉更糟,而且也不简洁。
那么我该如何在TypeScript中执行以下操作:
function doSomething( foo: Element ): string {
if( 'type' in foo ) {
return foo.type as string;
}
}
(当我确实使用上面的doSomething
代码时,TypeScript说foo
块内的if()
类型实际上是never
而不是Element
)
答案 0 :(得分:1)
如果current
(如果可能具有属性disabled
)将是HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement
之一,那么我认为最好的办法就是为此创建一个类型保护:
const isDisableableElement = (current: HTMLElement): current is HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement => {
return 'disabled' in current;
};
这不是简明扼要的,而是像您说的那样:
我的快速解决方案是添加这些类型断言(如下所示),但是感觉就像我做错了什么。特别是因为
ctrl
可能是HTMLSelectElement
的{{1}}或HTMLTextAreaElement
,但确实具有HTMLInputElement
属性
您必须在简洁和类型正确性之间进行选择,类型正确性可能是一个更好的选择,尤其是因为它不会添加太多的代码,简单明了且不会使未来的读者感到困惑。
然后,只需在检查disabled: boolean
属性之前检查条件中的类型防护:
.disabled
如果您愿意,您似乎还可以减少代码中的其他检查。如果if (
(isDisableableElement(current) && current.disabled) ||
参数输入正确,并且始终为ctrl
,则它(及其父对象)将始终具有HTMLElement
和style
的{{1}}属性子属性。 display
也永远不会是visibility
或current
,因为您已经在循环的底部进行了这些检查(而undefined
不会是{{1 }}-它只会是一个元素或null
)。代码永远不会超过循环的结尾-找到隐藏的父级并返回.parentNode
,或者找到最终的父级并返回undefined
:
null