打字稿:如何制作接受对象的类型,其键匹配通用但所有值都是值参数的映射函数
Posted
技术标签:
【中文标题】打字稿:如何制作接受对象的类型,其键匹配通用但所有值都是值参数的映射函数【英文标题】:Typescript: How to make type that accepts object which keys match generic but all values are map functions of value argument 【发布时间】:2020-05-22 12:15:44 【问题描述】:我想实现这样的类型:“我的所有键都递归地与类型 T 相同,但我所有的值都是接受此类键值并映射它的函数。
我试过下面的代码,但它没有推断出指定函数的返回类型并且递归是错误的
export type ObjectButAllKeyIsValueFn<T> =
[K in keyof T]?: ObjectButAllKeyIsValueFn<T[K]> | (<R>(value: T[K]) => R)
interface User
name: string,
surname: string,
address:
city: string,
country: string,
street: string
const z: ObjectButAllKeyIsValueFn<User> =
name: value => `Hello $value`,
address:
city: city => 1
;
更新: 我想实现这样但递归的东西,所以我必须正确地将 StupidPattern 映射到 Pattern
type StupidPattern<T> =
[K in keyof T]: StupidPattern<T[K]> | ((value: T[K]) => unknown)
type Pattern<T> =
[K in keyof T]: (value: T[K]) => unknown
type Result<T, P = Pattern<T>> =
[K in keyof P]: K extends keyof T
? P[K] extends (value: T[K]) => infer R
? R
: never
: never
declare function map <T> (pattern: Pattern<T>): (target: T) => Result<T, Pattern<T>>
declare function map <T> (pattern: Pattern<T>, target: T): Result<T, Pattern<T>>;
【问题讨论】:
((value: T[K]) => T[K])
如果我理解正确,返回值需要与参数相同
@Marv 不,它不是,您可以将值映射到任何类型,但我想在参数中保留该类型,并且在结果对象上具有正确的类型
【参考方案1】:
(<R>(value: T[K]) => R)
类型不是你要找的;本质上通用的R
是quantified 错误的方式。它的意思是“一个函数,其输入类型为T[K]
,其输出是调用者指定的任何类型R
。这实际上不可能安全地实现。大概你的意思是实现者应该能够指定R
,但是在TypeScript中没有干净的方式来用泛型来表示它......你可能会将R
作为ObjectButAllKeyIsValueFn
的另一个泛型参数,但是你需要一个R
T
的每个键。让我们备份并以不同的方式看待这个:
我们如何将ObjectButAllKeyIsValueFun
定义为这种类型:
export type ObjectButAllKeyIsValueFn<T> =
[K in keyof T]?: ObjectButAllKeyIsValueFn<T[K]> | ((value: T[K]) => unknown)
这种类型捕捉到了函数值属性可以返回任何类型的想法,只要你关心。但是,当然,简单地将一个值注释为ObjectButallKeyIsValueFn<User>
类型会丢弃一堆关于该值类型的信息;你不会知道每个函数返回什么类型,或者即使任何特定的属性是一个函数。
所以让我们放弃注释变量作为那种类型。相反,当我们创建值时,我们确保它们可分配到该类型而不扩大它们。这将为我们提供您想要的所有 IntelliSense。这是一个辅助函数及其对User
的应用:
const asObjType = <T>() => <U extends ObjectButAllKeyIsValueFn<T>>(u: U) => u;
const asObjUser = asObjType<User>();
这就是你如何称呼asObjUser()
:
const z = asObjUser(
name: value => `Hello $value`,
address:
city: city => 1
);
/* const z:
name: (value: string) => string;
address:
city: (city: string) => number;
;
*/
console.log(z.name("Fred")); // Hello Fred
这有效并跟踪z
的特定类型。它还可以捕获如下错误:
const oops = asObjUser(
name: 123, // error!
// number is not assignable to string | ((value: string) => unknown) | undefined
);
所以,希望这足以让您取得进步。祝你好运!
Playground link to code
【讨论】:
我无法理解您如何使用这种咖喱函数并正确获取类型。实际上,我的代码在 js 中正常运行,但无法在 typescript 中对其进行注释和重写。我想要实现的目标是一个允许通过其结构声明映射来映射值的函数。所以在我的我有一些模式对象,其键与我要映射的目标值完全相同,但值是接受目标“对象”值并映射它们的函数。另外问题是我在这里使用递归映射并且很难编写递归类型:P 我不太理解这条评论,也没有在您编辑的代码中看到问题。您能否确定是 minimal reproducible example 清楚地表明了您遇到的问题?祝你好运!以上是关于打字稿:如何制作接受对象的类型,其键匹配通用但所有值都是值参数的映射函数的主要内容,如果未能解决你的问题,请参考以下文章