代码之家  ›  专栏  ›  技术社区  ›  lobati

通过外部功能的窄字体脚本类型?

  •  0
  • lobati  · 技术社区  · 6 年前

    我试图用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
    }
    
    1 回复  |  直到 6 年前
        1
  •  3
  •   jcalz    6 年前

    这是一份工作 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 . 让我们看看它是否有效,按系统输入:

    declare const element: Element;
    
    if (assertType(element, HTMLInputElement) && (element.checked)) {
      // do something
    }
    


    更新

    如果你想让它更通用 作为要匹配的构造函数 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;
    }
    

    关键是让代码从两个重载中选择一个。第一个和以前一样,但是第二个限制了 预期类型 到运行时 运算符返回,并通过 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
    }
    

    似乎也能工作(不过还没有在运行时测试)。不过,我还是会回避那种人格分裂的功能。由你决定。祝你好运!