打字稿:如何在具有记录的结构上“应用”?

时间:2019-06-23 15:00:48

标签: typescript typescript-typings

让我们说,我们有一个结构保存一个记录,我们希望在该记录上apply另一个结构保存一个记录,该记录保存第一个结构的键的功能。 (基本上是Apply幻想土地规范的反面)

让我们首先定义一些我们将要使用的类型:

type Index = string|number|symbol

type Struct<R extends Record<Index, any>> = {
  readonly value: R
  apOn: <B>(fab: Struct<{[K in keyof R]?: (a: R[K], k: K) => B}>) =>
    Struct<{[K in keyof R]: B}>
}

然后解决结构本身

declare function newStruct<R extends Record<Index, any>> (value: R): Struct<R>

const struct = newStruct ({a: 1, b: true})

在为apOn方法参数Struct指定具有相同数量键且具有相同返回类型的函数的const withFuncsa = newStruct ({ a: (a: number) => `${a}`, b: (a: boolean) => `${a}`, }) const withFuncsb = newStruct ({ a: (a: number) => a > 0, }) const resa = struct.apOn (withFuncsa).value // as expected {a: string, b: string} const resb = struct.apOn (withFuncsb).value // as expected {a: boolean, b: boolean} 时,前两个te会按预期工作。

const withFuncsc = newStruct ({
  a: (a: number) => a > 0,
  b: (a: boolean) => `${a}`,
})

const resc = struct.apOn (withFuncsc).value
// breaks cause expect all returns type of this withFuncc function to be identical
// expected {a: boolean, b: string}

但是在返回类型不同时会中断:

compute-rw

它们是让它与不同返回类型一起工作的一种方法吗?

1 个答案:

答案 0 :(得分:1)

我们需要重新处理签名以推迟对B的决定,直到知道其计算的密钥为止。

type Struct<R extends Record<Index, any>> = {
  readonly value: R
  apOn: <F extends {[K in keyof Partial<R>]: (a: R[K], k: K) => any}>
      (fab: Struct<F>) =>  
          Struct<Omit<R, keyof F> & {[K in keyof F]: ReturnType<F[K]>}>
}

F是映射器记录。重要的是[K in keyof Partial<R>]: ...而不是[K in keyof R]?: ...,因为我们要确保可选修饰符不会展平为... | undefined。映射器存在,功能是否存在。

然后在返回类型中,我们将未映射的字段保留为相同的Omit<R, keyof F>,但对于所有映射字段,请使用映射器产生的类型{[K in keyof F]: ReturnType<F[K]>}

在智能感知中,中间类型看起来有些混乱,但是它们可以完成工作:

const t: {strings: string[], bools: boolean[]} = {
    strings: [resa.a, resa.b, resc.b],
    bools: [resb.a, resb.a, resc.a],
}

Playground link