代码之家  ›  专栏  ›  技术社区  ›  Sean Allred

确定用于联合接口的接口

  •  1
  • Sean Allred  · 技术社区  · 6 年前

    interface StringOp {
        (a: string, b: string): string;
    }
    interface NumberOp {
        (a: number, b: number): number;
    }
    function doThing(callback: StringOp | NumberOp) {
        if (callback is StringOp) {
            callback("a", "b");
        } else {
            callback(1, 2);
        }
    }
    

    我该怎么表达 callback is StringOp 作为类型检查?


    我试图将上面的内容简化为MWE,但是下面的内容更接近我的实际用例:

    interface TickFunction<T> {
      (val: T): void;
    }
    interface IndexedTickFunction<T> {
      (val: T, index: number): void;
    }
    function forEachTick<T>(callback: TickFunction<T> | IndexedTickFunction<T>) {
      ...
    }
    

    如果可能的话,我想继续打电话 forEachTick 使用箭头符号文字:

    • forEachTick<SomeType>((v) => { ... })
    • forEachTick<SomeType>((v,i) => { ... }) .
    1 回复  |  直到 6 年前
        1
  •  1
  •   shohrukh    6 年前

    在TS中,接口只存在于开发过程中,因此无法在运行时检查接口类型并执行smth。因此,在创建回调方法时,必须以某种方式在接口中包含一个“指示符”,以便将其设置为一些值。此指示器可用于在运行时检查回调类型。TS还提供 User-Defined Type Guards 最终的解决方案是:

    interface StringOp {
        opType: 'StringOp',
        (a: string, b: string): string;
    }
    interface NumberOp {
        opType: 'NumberOp',
        (a: number, b: number): number;
    }
    
    function isStringOp(op: StringOp | NumberOp): op is StringOp {
        return op.opType === 'StringOp';
    }
    
    function doThing(callback: StringOp | NumberOp) {
        if (isStringOp(callback)) {
            callback("a", "b");
        } else {
            callback(1, 2);
        }
    }
    

    根据更新后的问题,我添加了另一个示例:

    interface TickFunction<T> {
      (val: T): void;
    }
    interface IndexedTickFunction<T> {
      (val: T, index: number): void;
    }
    
    function isTickFn<T>(fn: TickFunction<T> | IndexedTickFunction<T>): fn is TickFunction<T> {
        // in your example the indicator might be the function length
        // because it indicates the number of arguments expected by the function
        return fn.length === 1;
    }
    
    // I guess you also have to pass arguments to this function in order to pass them to your callback methods
    function forEachTick<T>(callback: TickFunction<T> | IndexedTickFunction<T>, value: T, index?: number) {
      if (isTickFn(callback)) {
        callback(value);
      } else {
        callback(value, index);
      }
    }
    
    for (let i=0; i<10; i++) {
      forEachTick<string>((v: string) => console.log(v), 'some text');
    }
    for (let i=0; i<10; i++) {
      forEachTick<boolean>((v: boolean, index: number) => console.log(v, index), true, i);
    }
    
    推荐文章