我正在尝试编写一个外部函数以使用TypeScript缩小对象的类型,但是,一旦我退出逻辑,TypeScript似乎就失去了线程。我有以下代码:
if (element instanceof HTMLInputElement && element.checked) {
// do something
}
但是,我想进行第一次结帐并向我们发送通知,告知发生问题:
function assertType(element, expectedType) {
if (element instanceof expectedType) { return true; }
notify(`element ${element} wasn't expected type ${expectedType}`);
return false;
}
if (assertType(element, HTMLInputElement) && element.checked) {
// do something
}
TypeScript对第一个感到满意,但第二个却抱怨:
error TS2339: Property 'checked' does not exist on type 'HTMLElement'.
即使我将其减少到最低限度,它仍然会失败:
function assertType(element, expectedType) {
return element instanceof expectedType;
}
有没有一种方法可以编写assertType
函数,以便TypeScript可以缩小类型?我试图避免进行类型转换以确保类型与基础html一致,但我想我可以在紧要关头使用它。甚至可能像这样:
if (assertType(element, HTMLInputElement) && (element as HTMLInputElement).checked) {
// do something
}
答案 0 :(得分:3)
这是user-defined type guards和generics的工作,因此它可以应用于任何类型。这是一种使您的assertType
函数的方法:
function assertType<T>(element: any, expectedType: new(...args: any[])=>T): element is T {
return element instanceof expectedType;
}
这个想法是expectedType
应该是某个通用类型T
的构造函数,并且它将返回是否element is T
。让我们看看它是否有效,键入system wise:
declare const element: Element;
if (assertType(element, HTMLInputElement) && (element.checked)) {
// do something
}
没有错误。希望能有所帮助。祝你好运!
如果要使其更加通用并允许
expectedType
成为与instanceof
匹配的构造函数或与typeof
匹配的字符串怎么办?
要执行一个函数似乎有点困难,但是如果尝试尝试,我可能会使用overloads和lookup types,如下所示:
type TypeofMapping = {
string: string,
number: number,
boolean: boolean,
symbol: symbol,
undefined: undefined,
object: object,
function: Function
}
function assertType<T>(element: any, expectedType: new (...args: any[]) => T): element is T;
function assertType<K extends keyof TypeofMapping>(element: any, expectedType: K): element is TypeofMapping[K];
function assertType(element: any, expectedType: new (...args: any[]) => any | keyof TypeofMapping): boolean {
return (typeof expectedType === "string") ? typeof element === expectedType : element instanceof expectedType;
}
重点是让代码选择两个重载之一。第一个与以前一样,但是第二个将expectedType
约束为运行时typeof
运算符返回的字符串之一,并通过TypeofMapping
将该字符串映射为类型。让我们再试一次:
declare const element: Element;
if (assertType(element, HTMLInputElement) && (element.checked)) {
// do something
}
declare const otherThing: string | number;
if (assertType(otherThing, "string") && otherThing.charAt(0) === 'a') {
// do something else
}
似乎也可以工作(尽管尚未在运行时进行测试)。不过,我自己还是会回避这种分裂人格的功能。由你决定。再次祝你好运!