我有以下生成器函数:

async function * filterIterable (iter, predicate) {
  let i = 0
  for await (const val of iter) {
    if (predicate(val, i++)) {
      yield val
    }
  }
}

我想为以下两种情况输入:

// type predicate
const nonNullable = <T>(val: T | undefined | null): val is T =>
  val !== undefined && val !== null

async function * gen1 () {
  yield 1
  yield 2
  yield 3
}

async function * gen2 () {
  yield 1
  yield undefined
  yield 3
}

const it1 = filterIterable(gen1(), n => n % 2 === 0)
const it2 = filterIterable(gen2(), nonNullable) // should be AsyncIterable<1 | 2>

我想出了这个界面:

interface FilterIterable {
  <T> (
    iter: AsyncIterable<T>,
    predicate: (val: T, index: number) => boolean,
  ): AsyncIterable<T>;
  <T, S extends T> (
    iter: AsyncIterable<T>,
    predicate: (val: T, index: number) => val is S,
  ): AsyncIterable<S>;
}

我可以将其应用于函数表达,但显然不能应用于每How to apply a function type to a function declaration个函数声明.这不就是发电机吗?

推荐答案

因此,您希望filterIterable()成为具有多个调用签名的overloaded函数.虽然您目前确实无法按照microsoft/TypeScript#22063中的请求直接注释函数,但您可以使用常规的重载语法并在实现之前声明调用签名:

// call signatures
function filterIterable<T, S extends T>(
  iter: AsyncIterable<T>, predicate: (val: T, index: number) => val is S
): AsyncIterable<S>;
function filterIterable<T>(
  iter: AsyncIterable<T>, predicate: (val: T, index: number) => boolean
): AsyncIterable<T>;

// implementation
async function* filterIterable<T>(
  iter: AsyncIterable<T>, predicate: (val: T, index: number) => boolean
) {
  let i = 0
  for await (const val of iter) {
    if (predicate(val, i++)) {
      yield val
    }
  }
}

这现在应该按照您的预期工作:

async function foo() {
  const it1 = filterIterable(gen1(), n => n % 2 === 0)
  for await (const x of it1) {
    //             ^? const x: 1 | 2 | 3
    console.log(x.toFixed(2))
  }
  const it2 = filterIterable(gen2(), nonNullable) 
  for await (const y of it2) {
    //             ^? const y: 1 | 3
    console.log(y.toFixed(3))    
  }
}

Playground link to code

Typescript相关问答推荐

当两个参数具有相同的通用类型时,如果没有第一个参数,则递减约束默认会导致第二个参数的错误推断

为什么当我试图从数据库预填充时,属性x不存在于类型{错误:字符串; }.ts(2339)上?

创建一个将任意命名类型映射到其他类型的TypScript通用类型

排序更改数组类型

Tailwind CSS样式不在Svelte应用程序中呈现

node—redis:如何在redis timeSeries上查询argmin?

使某些类型的字段变为可选字段'

如何修复正在处理类型但与函数一起使用时不处理的类型脚本类型

如果字符串文字类型是泛型类型,则用反引号将该类型括起来会中断

如何将CSV/TXT文件导入到服务中?

TS2339:类型{}上不存在属性消息

为什么我的查询钩子返回的结果与浏览器的网络选项卡中看到的结果不同?

如何在方法中正确地传递来自TypeScrip对象的字段子集?

基元类型按引用传递的解决方法

@TANSTACK/REACT-QUERY中发生Mutations 后的数据刷新问题

如何将对象数组中的键映射到另一种对象类型的键?

为什么上下文类型在`fn|curred(Fn)`的联合中不起作用?

是否可以通过映射类型将函数参数约束为预定义类型?

如何将元素推入对象中的类型化数组

如何在TypeScript中声明逆变函数成员?