一般从类型记录中提取一个值
Generically extract a value from typed Record
我使用的是 fp-ts,在本例中是选项。
假设我有一个示例类型:
import * as O from 'fp-ts/Option';
type ExampleType = {
a: number,
b: O.Option<number>,
c: O.Option<string>
}
以及这些类型的记录:
type ExampleRecord = Record<string, ExampleType>
我多次发现相同的“主题”:
我想写一个通用函数,给定一个 属性 名称和记录类型(可以是 ExampleType 或任何其他至少有一个选项 属性 的类型),将它变成:
const a: ExampleRecord = { key1: {a: 1, b: O.none, c: O.some('example')}, key2: { a: 2, b: O.some(3), c: O.none } }
进入这个:
const b = f('b', a) // b is { key2: { a: 2, b: 3, c: O.none } }
注意我给了它 b 键,它过滤了所有没有 b 值的记录,同时从选项中提取值以防它存在并 returning 它。
但是,我不知道如何在不丢失类型信息的情况下键入这样的函数 f。 return 类型应该是这样的:
type TheReturnType = Record<string, ExampleType & {b: number}>
但我无法弄清楚如何动态推断这一点(如果可能的话)。我的意思是,b: 数字来自 b 是 T 中的 O.Option 这一事实,但由于 b 是动态的,因此很难实际推断出任何东西。
有没有人有什么想法?
您可以使用条件类型提取选项的类型。然后,您可以使用通用函数来捕获记录类型(我们称之为 T
)和键的类型(我们称之为 K
)。有了这些信息,您就可以创建所需的类型,方法是从 T
中省略 K
并将其与仅包含 K
且选项类型为 [=17] 的对象类型相交=]
const a: ExampleRecord = { key1: { a: 1, b: O.none, c: O.some('example') }, key2: { a: 2, b: O.some(3), c: O.none } }
type OptionValue<T extends O.Option<any>> = T extends O.Some<infer U> ? U: never;
function f<T extends Record<K, O.Option<any>>, K extends keyof T>(key: K, value: Record<string, T>): Record<string, Omit<T, K> & Record<K, OptionValue<T[K]>>> {
return null!;
}
const b = f('b', a) // b is { key2: { a: 2, b: 3, c: O.none }
b["key2"].b.toExponential // number
我使用的是 fp-ts,在本例中是选项。 假设我有一个示例类型:
import * as O from 'fp-ts/Option';
type ExampleType = {
a: number,
b: O.Option<number>,
c: O.Option<string>
}
以及这些类型的记录:
type ExampleRecord = Record<string, ExampleType>
我多次发现相同的“主题”: 我想写一个通用函数,给定一个 属性 名称和记录类型(可以是 ExampleType 或任何其他至少有一个选项 属性 的类型),将它变成:
const a: ExampleRecord = { key1: {a: 1, b: O.none, c: O.some('example')}, key2: { a: 2, b: O.some(3), c: O.none } }
进入这个:
const b = f('b', a) // b is { key2: { a: 2, b: 3, c: O.none } }
注意我给了它 b 键,它过滤了所有没有 b 值的记录,同时从选项中提取值以防它存在并 returning 它。
但是,我不知道如何在不丢失类型信息的情况下键入这样的函数 f。 return 类型应该是这样的:
type TheReturnType = Record<string, ExampleType & {b: number}>
但我无法弄清楚如何动态推断这一点(如果可能的话)。我的意思是,b: 数字来自 b 是 T 中的 O.Option 这一事实,但由于 b 是动态的,因此很难实际推断出任何东西。
有没有人有什么想法?
您可以使用条件类型提取选项的类型。然后,您可以使用通用函数来捕获记录类型(我们称之为 T
)和键的类型(我们称之为 K
)。有了这些信息,您就可以创建所需的类型,方法是从 T
中省略 K
并将其与仅包含 K
且选项类型为 [=17] 的对象类型相交=]
const a: ExampleRecord = { key1: { a: 1, b: O.none, c: O.some('example') }, key2: { a: 2, b: O.some(3), c: O.none } }
type OptionValue<T extends O.Option<any>> = T extends O.Some<infer U> ? U: never;
function f<T extends Record<K, O.Option<any>>, K extends keyof T>(key: K, value: Record<string, T>): Record<string, Omit<T, K> & Record<K, OptionValue<T[K]>>> {
return null!;
}
const b = f('b', a) // b is { key2: { a: 2, b: 3, c: O.none }
b["key2"].b.toExponential // number