代码之家  ›  专栏  ›  技术社区  ›  Ran Lottem

包含原语的泛型类型保护

  •  0
  • Ran Lottem  · 技术社区  · 6 年前

    function typeGuard<T>(o, constructor: { new(...args: any[]): T }): o is T {
        return o instanceof constructor;
    }
    

    这适用于任何具有构造函数的类,例如:

    class b {
        k: number;
    
        constructor(k: number) {
            this.k = k;
        }
    }
    console.log(typeGuard(new b(5), b));
    

    我很难让它工作,比如:

    console.log(typeGuard(5, number));
    

    console.log(typeGuard<number>(5));
    

    type prim = "string" | "number" | "boolean"; // or without quotes
    function typeGuard<T>(o, constructor: { new(...args: any[]): T }): o is T;
    function typeGuard<T extends prim>(o): o is T;
    function typeGuard<T>(o, constructor?): o is T {
        if (constructor) {
            return o instanceof constructor;
        }
    return typeof o ==="string";
    }
    

    if typeof o === T 或者类似的。

    有没有办法实现这一点?理论上我想通过 string 作为 constructor typeGuard(5, string) 建造师 s类型为: { new(...args: any[]): T } | Type<string> | Type<number> | Type<boolean> 但我不知道如何在typescript中实现这个。

    class firstClass {
        n: number;
        constructor(n: number) {
            this.n = n;
        }
    }
    
    class secondClass {
        id: Date;
        constructor(d: Date) {
            this.id = d;
        }
    }
    
    function toConsole(a): void {
        if (typeGuard(a, firstClass)) {
            console.log(a.n);
        } else if (typeGuard(a, secondClass)) {
            console.log(a.id);
        } else if (typeGuard(a, string)) {
            console.log(a);
        }
    }
    
    1 回复  |  直到 6 年前
        1
  •  1
  •   jcalz    4 年前

    我仍然不确定这个函数的真正需求是什么,但是让我们看看我们能做些什么。您需要在运行时为函数提供一个值,用于确定您是在检查字符串、数字还是其他内容。

    假设第二个论点 typeGuard() 被称为 sentinel ,类型 Sentinel ,可以是构造函数,也可以是与 typeof 给你的。

    type TypeofMap = {
      string: string,
      number: number,
      boolean: boolean
    }
    type Sentinel = (new (...args: any[]) => any) | keyof TypeofMap;
    

    然后,给定一个类型的值 哨兵 通过以下途径 conditional type :

    type GuardedType<T extends Sentinel> = T extends new (...args: any[]) => infer U ? 
      U : T extends keyof TypeofMap ? TypeofMap[T] : never;
    

    你可以实现 这样地:

    function typeGuard<T extends Sentinel>(value: any, sentinel: T): value is GuardedType<T> {
      // assign to Sentinel instead of generic T to allow type guarding†
      const concreteSentinel: Sentinel = sentinel;
      if (typeof concreteSentinel === "string") {
        return typeof value === concreteSentinel;
      } else {
        return value instanceof concreteSentinel;
      }
    }
    

    (见 Microsoft/TypeScript#13995 concreteSentinel )

    declare const thing: string | number | RegExp;
    if (typeGuard(thing, "string")) {
      console.log(thing.charAt(0));
    } else if (typeGuard(thing, RegExp)) {
      console.log(thing.flags);
    } else {
      console.log(thing.toFixed(0));
    }
    

    这有道理吗?

    推荐文章