将对象的可观察对象转换为可观察对象

时间:2020-08-27 13:34:15

标签: typescript rxjs

我正在尝试创建一个将对象的Observable对象(本身就是Observable的集合)转换为Observables对象的函数
当前的实现如下所示:

type Inputs = {[inputName: string]: Observable<unknown>}

export const transform = <Inp extends Inputs, Keys extends keyof Inputs>(
  inputs$: Observable<Inp>,
  inputNames: Keys[],
) => {
  const cachedSinks$ = inputs$.pipe(share())

  return inputNames.reduce((result, inpName) => {
    result[inpName] = cachedSinks$
      .pipe(switchMap(sinks => sinks[inpName]))
    return result
  },
  {} as {[K in Keys]: Inp[Keys]})
}

但是我在result[inpName] = cachedSinks$行出现了一个错误TS2322: Type 'Observable >' is not assignable to type 'Inp[Keys]'.,而且我不明白为什么会这样,因为Inp[Keys]也是可观察的

3 个答案:

答案 0 :(得分:1)

type Inputs = {[inputName: string]: Observable<unknown>}

export const transform = <Inp extends Inputs, Keys extends keyof Inputs>(
  inputs$: Observable<Inp>,
  inputNames: Keys[],
)

此处的关键部分是Keys extends keyof Inputs。输入是一种类型,您从中不知道任何特定的键。我相信您的意思是Inp,即提供给该函数的类型。试试

type Inputs = {[inputName: string]: Observable<unknown>}

export const transform = <Inp extends Inputs, Keys extends keyof Inp>(
  inputs$: Observable<Inp>,
  inputNames: Keys[],
)

答案 1 :(得分:1)

T [K]必须扩展类型这一事实并不意味着我们可以在泛型函数中为其分配任何值,约束条件只是告诉我们该值的最低要求是什么,我们尚不知道T [K]要求的完整合同。 (Titian Cernicova-Dragomir's post

假设我们将以下Intersection类型的实例传递给transform

type ExtendedInputs = Inputs & {
    age: number
}

将可观察对象分配给result[inpName]是不安全的,因为result[inpName]可能是数字。

考虑到这一点,请考虑将tranform函数修改为直接使用Input而不是使用泛型(因为在这种情况下似乎没有必要),如下所示:

export const transform = <K extends keyof Inputs>(
    inputs$: Observable<Inputs>,
    inputNames: K[],
) => {
    const cachedSinks$ = inputs$.pipe(share())

    return inputNames.reduce((result, inpName) => {
        result[inpName] = cachedSinks$.pipe(switchMap(sinks => sinks[inpName]))

        return result
    }, {} as Inputs })
}

更新
如果您确定该值可分配给type assertion

,则可以使用T[K]将其保留为通用。
export const transform = <T extends Inputs, K extends keyof T>
  (inputs$: Observable<T>, inputNames: K[]) => {
  const cachedSinks$ = inputs$.pipe(share())


  return inputNames.reduce((result, inpName) => {

    result[inpName] = cachedSinks$.pipe(switchMap(sinks => sinks[inpName])) as T[K]

    return result

  }, {} as T)

}

(可选,(再次,仅当您确定该值可分配给T[K]时才使用此选项)

 export const transform = <T extends Inputs, K extends keyof T>
   (inputs$: Observable<T>, inputNames: K[]) => {
   const cachedSinks$ = inputs$.pipe(share())
 
   return inputNames
     .reduce((result, inpName) => ({ ...result, [inpName]: cachedSinks$.pipe(switchMap(sinks => sinks[inpName])) }), {})
 }

答案 2 :(得分:0)

我在类型定义中犯了两个错误,现在它可以正常工作了
1个错误:{} as {[K in Keys]: Inp[Keys]})应该为{} as {[K in Keys]: Inp[K]})
2个错误:<Inp extends Inputs, Keys extends keyof Inputs>应该是<Inp extends Inputs, Keys extends keyof Inp>