让我们说,我们有一个结构保存一个记录,我们希望在该记录上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
它们是让它与不同返回类型一起工作的一种方法吗?
答案 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],
}