typescript - 转换接口,使得一个类型的出现被另一个类型的打字稿替换
问题描述
我有一个函数可以遍历给定的泛型对象(T 类型),然后将某种类型的某些道具转换为不同的类型。我需要这个函数来更新输入类型 (T) 以反映函数所做的输入变化。
我正在尝试完成以下任务:给定Interface1
:
interface Interface1 {
prop1: Type1
prop2: Type2
prop3: {
subprop1: Type1
subprop2: Type2
}
}
然后我需要一个类型表达式Transform<T>
,这样Transform<Interface1>
会导致:
interface Interface2 {
prop1: NewType
prop2: Type2
prop3: {
subprop1: NewType
subprop2: Type2
}
}
解决方案
This can be done - but at what cost?
It might be worth trying to see if there's a way you can do what you want to do in a simpler manner. There's not a lot of context so I can't advise on how you would approach this - I usually try and stay away from stuff like this for maintainability reasons.
This will do what you're asking - where T is the object type to transform, TTarget is Type1 and TResult is NewType
First - the simpler form which lazily evaluates. This means you get the following output when hovering over the result type:
type Transform1<T extends object, TTarget, TReplacement> = {
[key in keyof T]:
T[key] extends object
? Transform1<T[key], TTarget, TReplacement>
: T[key] extends TTarget ? TReplacement : T[key];
}
This version will eagerly evaluate the nested object - giving you more 'correct' looking type hints
type Transform2<T extends object, TTarget, TReplacement> = {
[key in keyof T]:
T[key] extends object
? {
[innerKey in keyof Transform2<T[key], TTarget, TReplacement>]:
Transform2<T[key], TTarget, TReplacement>[innerKey]
}
: T[key] extends TTarget ? TReplacement : T[key];
}
How this works is that we first map over T using a mapped type -
{ [key in keyof T]: T[key] }
Next we need to check if T[key] is a nested object, and if so - we need to recurse the type. We do this by asking if T[key] extends object
. If it does, Transform<T[key], TTarget, TResult>
again.
Then we can check if T[key] is assignable to the TTarget we are trying to replace with T[key] extends TTarget
. If it does, return TReplacement, otherwise leave it alone by returning T[key].
The eagerly evaluated version just uses a little trick where we map over the result type again.
We are doing the same {[key in T]: T[key]}
- except we replace T with the thing we want to evaluate - which is Transform<T[key], TTarget, TResult>
. We also need another variable for key, because we're now mapping over the inner type, so I used innerKey here.
This gives us
{ [innerKey in keyof Transform2<T[key], TTarget, TReplacement>]: Transform2<T[key], TTarget, TReplacement>[innerKey] }
推荐阅读
- sapui5 - SAPUI5计划日历需要一行中的约会
- swift-package-manager - Swift 包管理器 - 带有 .zip 文件的 binaryTarget 无法验证
- javascript - 在 Vuejs SPA 中存储密码和私钥等敏感数据的安全方法是什么?
- html-framework-7 - Framework7 强制重新加载页面或根本不缓存它们
- karate - 通过 XPath 使用空手道中的变量获取元素
- python - 如何在python数据框中添加列标题或重命名列标题
- fortran - 在fortran中生成-1.5到1之间的随机实数
- asp.net-core - 如何有条件地禁用 ASP.NET Core 中的 Application Insights?
- php - 准备php postgresql时转义字符串
- python - Discord.py 频道创建和设置权限不起作用