How to create function that will return a function with type inference using generics in typescript

huangapple go评论59阅读模式
英文:

How to create function that will return a function with type inference using generics in typescript

问题

// 这是返回的函数
const suppliedFunction = <T>(args: T) => {
    return true;
}; // 这是返回的函数

// 所以我可以这样使用它
suppliedFunction({ prop: "value" });

// 函数生成器,从参数返回供应的函数
// 提供的函数应该返回一个布尔值
function generateFunction(fn: <T>(args: T) => boolean) {
    return fn;
}

// 但是这段代码给我一个错误
// 属性'prop'在类型'unknown'上不存在
const resultFunction = generateFunction(({ prop }) => {
    return true;
});

// 我的目标是我可以根据生成的函数来使用resultFunction进行类型推断(而不是显式编写类型)
// 这应该引发错误
// 类型为'string'的参数无法分配给类型为'{ prop: any; }'的参数
resultFunction('text');

// 这应该没问题
resultFunction({ prop: "winter" });
英文:

Let say i want to run generateFunction() that will return this function:

// This is the returned function
const suppliedFunction = &lt;T&gt;(args: T) =&gt; {
	return true;
}; // This is the returned function

// so I can use it like this
suppliedFunction({ prop: &quot;value&quot; }); 

I decided to create the generatorFunction like this:

// Function generator, returning supplied function from the parameter
// The supplied function should returning a boolean
function generateFunction(fn: &lt;T&gt;(args: T) =&gt; boolean) {
	return fn;
}

// But this code gives me an error
// Property &#39;prop&#39; does not exist on type &#39;unknown&#39;
const resultFunction = generateFunction(({ prop }) =&gt; {
	return true;
});

My goal is i could use resultFunction with type inference based on generated function (not by explicitly writing the type

// This should gives an error
// Argument of type &#39;string&#39; is not assignable to parameter of type &#39;{ prop: any; }&#39;
resultFunction(&#39;text&#39;);

// This should be OK
resultFunction({ prop: &quot;winter&quot; });

How do we really implement this generics for my case? Thakks in advance.

答案1

得分: 0

实际上,我在解决了三天的问题后,终于找到了我想要的东西,感谢[@jcalz](https://stackoverflow.com/users/2887218/jcalz)在[此答案](https://stackoverflow.com/questions/51851677/how-to-get-argument-types-from-function-in-typescript)中提供的帮助,我可以使用基于泛型的自定义ArgumentTypes和custom ReturnTypes。由于在我的项目中,使用typescript的Parameters&lt;&gt;和ReturnType&lt;&gt;工具不起作用,所以我决定使用该答案中提供的自定义实用程序,然后我创建了这个。

它工作得很好,动态地支持操作重载函数,因此可以保证类型安全。如果你不希望将文档对象模型值作为参数传递并从提供的函数返回类型传递给生成器,你可以将其添加到Serializables类型以限制类型

[在这里查看它的运行情况](https://tsplay.dev/mpxBzm)
英文:

Actually i just found what I wanted, after 3 days of solving this, thanks to @jcalz from this post answer i could use custom ArgumentTypes and custom ReturnTypes based on generics. Somehow, using Parameters<> and ReturnType<> utilities from typescript is not working for my project so I decided to use custom utility provided from that answer, then I made this

type Serializables =
	| Function
	| PropertyDescriptor
	| Document
	| Omit&lt;RegExp, &quot;lastIndex&quot;&gt;
	| never;

type SerializableParam&lt;Serializable&gt; = Serializable extends Serializables
	? unknown
	: Serializable;

type SerializableReturnType&lt;Serializable&gt; =
	Serializable extends Serializables | void ? never : Serializable;

type ArgumentTypes&lt;F extends Function&gt; = F extends (...args: infer A) =&gt; any
	? A
	: never;

type ReturnType&lt;F extends Function&gt; = F extends (...args: any) =&gt; infer A
	? A
	: never;

interface SupplierFunction&lt;T, Payload&gt; extends Function {
	(arg0?): Payload extends undefined
		? never
		: SerializableReturnType&lt;ReturnType&lt;T &amp; Function&gt;&gt;;
	(arg0: SerializableParam&lt;Payload&gt;): SerializableReturnType&lt;
		ReturnType&lt;T &amp; Function&gt;
	&gt;;
	(...arg0: SerializableParam&lt;Payload&gt;[]): Payload extends undefined
		? never
		: SerializableReturnType&lt;ReturnType&lt;T &amp; Function&gt;&gt;;
}

export default function generateFunction&lt;F&gt;(
	fn: F &amp; SupplierFunction&lt;F, ArgumentTypes&lt;F &amp; Function&gt;[0]&gt;
) {
	return async (payload: ArgumentTypes&lt;F &amp; Function&gt;[0]) =&gt; {
		const result: SerializableReturnType&lt;ReturnType&lt;F &amp; Function&gt;&gt; =
			await new Promise((resolve) =&gt; {
				resolve(fn(payload));
			});
		return await result;
	};
}

It works like charm, dynamically and also support manipulating overloading functions so it can be typesafed. If you dont want document object model value passed as parameter and return types from the supplied function to the generator, you can add it to Serializables type to restrict the types.

Check this out in action

huangapple
  • 本文由 发表于 2023年5月30日 01:06:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/76359157.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定