为HOF获得typeguard防护类型

时间:2017-12-15 19:06:27

标签: typescript

我有以下简单的HOF

function myHOF(input: any, typeguard: (thing: any) => boolean) {
  if (typeguard(input)) {
    return input;
  }
}

使用typeguard功能

function myTypeguard(input: any): input is Array<any> {
  return Array.isArray(input);
}

用作

const val = [1,2];
const thing = myHOF(val, myTypeguard);  // <- should be Array<any> | undefined

显然,这过于简单,但这种类型的东西在创建通用的树遍历HOF时变得很重要。这个语言有兼容性吗?

更有趣的例子

export function* depthFirstRetrieval<T=PlanNode, L=PlanNode>(
  jxml: T,
  stopConditional: (obj: PlanNode) => boolean,
) {
  if (stopConditional(jxml)) {
    yield jxml;
  } else {
    for (const key of Object.keys(jxml) as Array<keyof typeof jxml>) {
      const property = jxml[key];
      if (Array.isArray(property)) {
        for (const childNode of property) {
          yield *depthFirstRetrieval(childNode, stopConditional);
        }
      }
    }
  }
}

应该产生类型L

1 个答案:

答案 0 :(得分:2)

当然,您可以在高阶函数中使用类型保护签名。事实上,TypeScript standard library's type definition for Array.filter()使用它来允许您返回比您过滤的数组更窄的数组:

  

interface Array { filter( callbackfn: (value: T, index: number, array: T[]) => value is S, thisArg?: any ): S[];

无论如何,对于你的例子:

function myHOF<T>(input: any, typeguard: (thing: any) => thing is T) : T | undefined {
  if (typeguard(input)) {
    return input;
  }
  return;
}

myHOF()中的T是通用的,因为您希望使用类型保护输出您测试的相同类型T。另请注意typeguard参数如何注释为返回类型谓词thing is T的函数。

现在您可以按预期使用它:

function myTypeguard(input: any): input is Array<any> {
  return Array.isArray(input);
}

const val = [1,2];
const thing = myHOF(val, myTypeguard);  // thing is any[] | undefined

编辑:我对PlanNode的其他案例不是100%肯定,但可能是这样:

export function* depthFirstRetrieval<T extends PlanNode, L extends PlanNode>(
  jxml: T,
  stopConditional: (obj: PlanNode) => obj is L,
): IterableIterator<L>
{
  if (stopConditional(jxml)) {
    yield jxml;
  } else {
    for (const key of Object.keys(jxml) as Array<keyof typeof jxml>) {
      const property = jxml[key];
      if (Array.isArray(property)) {
        for (const childNode of property) {
          yield *depthFirstRetrieval(childNode, stopConditional);
        }
      }
    }
  }
}

希望有所帮助;祝你好运!