typescript - 为类型安全的 Mappers 捕获 Typescript 映射函数结果类型
问题描述
我试图描述围绕 JSON 映射函数的强类型安全约束。此函数将对象作为第一个参数,并使用作为第二个参数传递的映射函数返回此对象的映射表示。
从消费者的角度来看,类似于此合同:
let mappedResult = mapJson(
// Standard plain object literal coming, most of the time from serverside, generally described by an interface
// Let's call this type SRC
{ date: "2018-10-04T00:00:00+0200", date2: 1538604000000, aString: "Hello%20World", idempotentValue: "foo" },
// Applying some mapping functions to convert input values above to a different type representation. Let's call this type MAPPING.
// Rules are :
// - Keys should be a subset of SRC's keys
// - Values should be functions taking SRC[key] and returning a new type NEW_TYPE[key] we want to capture in order to reference it in mapJson()'s result type
{ date: Date.parse, date2: (ts: number) => new Date(ts), aString: unescape }
); // Result type should be something like {[key in SRC]: RESULT[key] ... and SRC[key] if undefined}
// Expecting to get mappedResult = { date: Date.parse("2018-10-04T00:00:00+0200"), date2: new Date(1538604000000), aString: unescape("Hello%20World"), idempotentValue: "foo" }
// Meaning that expected type would be { date: number, date2: Date, aString: string, idempotentValue: string }
我遇到了多种复杂性:
- 通过键捕获映射函数返回类型
- 在结果中使用这个捕获的类型......如果在 NEW_TYPE 中找不到,则使用 SRC 类型(类似于联合类型,但不完全一样)
我尝试了这样的事情,但我什至不能让 1/ 工作(我知道 2/ 在这种情况下不应该工作),因为 mapJson() 结果值类型是类型any
:
function mapJson<
SRC extends object,
// That's a 'capture-only' type definition here, used as a placeholder for mappings' return types
CAPTURED_TARGET_MAPPINGS_TYPES extends {[ATTR in keyof SRC]?: CAPTURED_TARGET_MAPPINGS_TYPES[ATTR]} ,
TARGET_MAPPINGS extends {[ATTR in keyof SRC]?: (value: SRC[ATTR], obj?: SRC) => CAPTURED_TARGET_MAPPINGS_TYPES[ATTR]}
>(src: SRC, mappings: TARGET_MAPPINGS): {[ATTR in keyof SRC]: CAPTURED_TARGET_MAPPINGS_TYPES[ATTR]} {
// implementation here... not the purpose of this question :-)
}
我的目的是真正拥有强大的类型安全函数签名(用于输入和输出),我想知道 Typescript 3.1 目前是否可以处理这种情况。
如果您有空闲时间可以提供帮助,我将不胜感激:-)
解决方案
我不会CAPTURED_TARGET_MAPPINGS_TYPES
对映射类型使用额外的,我只会使用条件类型来获取函数的返回类型(如果没有指定类型映射,则为原始类型,如idempotentValue
)
type FunctionMap<SRC> = {[ATTR in keyof SRC]?: (value: SRC[ATTR], obj?: SRC) => any}
type MappedReturnType<SRC,TARGET_MAPPINGS extends FunctionMap<SRC>> ={
[ATTR in keyof SRC]: [TARGET_MAPPINGS[ATTR]] extends [undefined] ? SRC[ATTR] : ReturnType<Extract<TARGET_MAPPINGS[ATTR], Function>>
}
function mapJson<
SRC,
TARGET_MAPPINGS extends FunctionMap<SRC>
>(src: SRC, mappings: TARGET_MAPPINGS): MappedReturnType<SRC, TARGET_MAPPINGS>{
return null as any;
// implementation here... not the purpose of this question :-)
}
let mappedResult = mapJson(
// Standard plain object literal coming, most of the time from serverside, generally described by an interface
// Let's call this type SRC
{ date: "2018-10-04T00:00:00+0200", date2: 1538604000000, aString: "Hello%20World", idempotentValue: "foo" },
// Applying some mapping aimed at converting input values above and change their type representation. Let's call this type MAPPING.
// Rules are :
// - Keys should be a subset of SRC's keys
// - Values should be function taking SRC[key] and returning a new type NEW_TYPE[key] we want to capture in order to reference it in mapJson()'s result type
{ date: Date.parse, date2: (ts: number) => new Date(ts), aString: unescape }
);
let s = mappedResult.idempotentValue // string
let s2 = mappedResult.date2//Date
let s3 = mappedResult.date // number
这应该可以追溯到 2.8,不确定您当前使用的版本。
推荐阅读
- sql - SQL 查询未获取任何值
- sql - 选择查询中具有未知数据类型和多个连接的动态列立即执行 - Oracle 存储过程
- javascript - 使用 Javascript 创建 html 自定义标签
- php - Doctrine 只返回相关实体的一个参数
- javascript - 如何清除所有输入字段的值?
- rust - 由于拒绝访问(生锈/货物)导致无法锁定文件
- django - Django REST 框架中的批量获取
- r - 使用 ggplot2 标记条形图并将颜色更改为条形图
- notepad++ - 如何在 Notepad++ 中扩展现有语言模型
- vhdl - 未初始化的端口没有驱动程序。VHDL建模问题