【问题标题】:Transform Observable of objects into object of Observables将对象的 Observable 转换为 Observables 的对象
【发布时间】:2020-12-16 09:46:56
【问题描述】:

我正在尝试创建一个函数,将 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 &gt;' is not assignable to type 'Inp[Keys]'. 行出现错误,我不明白为什么会发生这种情况,因为 Inp[Keys] 也是一个 Observable

【问题讨论】:

    标签: typescript rxjs


    【解决方案1】:

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

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

    type ExtendedInputs = Inputs & {
        age: number
    }
    

    将 Observble 分配给 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 })
    }
    

    更新
    如果您确定该值可分配给T[K],则可以使用type assertion 保持其通用性

    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】:

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

    【讨论】:

    • 你确定它有效吗?你没有任何错误?
    • 以下代码不应该工作:` type Inputs = {[inputName: string]: Observable} export const transform = ( inputs$: Observable, 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[K]}) }`
    • @RafiHenig,你是对的,问题仍然存在,我不能直接使用 Inputs,因为它应该是一个通用实用程序
    【解决方案3】:
    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。 Inputs 是一种类型,您不知道任何特定的键。我相信你的意思是 Inp,它是提供给函数的类型。试试

    type Inputs = {[inputName: string]: Observable<unknown>}
    
    export const transform = <Inp extends Inputs, Keys extends keyof Inp>(
      inputs$: Observable<Inp>,
      inputNames: Keys[],
    )
    

    【讨论】:

    • 你是对的,我犯了2个错误,现在它可以正常工作了,谢谢
    猜你喜欢
    • 2021-12-04
    • 2013-08-27
    • 2017-11-05
    • 2017-08-15
    • 1970-01-01
    • 2013-07-29
    • 2020-05-30
    • 2023-04-03
    • 1970-01-01
    相关资源
    最近更新 更多