[英]Is there a way to constrain a generic type parameter to generic types?
有没有办法将泛型类型参数限制为泛型类型?
//I can constrain a parameter to only object types like this
type GenericType<T extends object> = keyof T ...
//How can I do that for generic types?
type GenericModifier<T extends /* Generic<T> */> = T<...>
//I want to do something like this:
type Distribute<target, type> = type extends infer A ? target<A> : never;
那可能吗?
你可能会做这样的事情
/**
* Forces windening but keeps the structure e.g. ["a","b"] => [string, string]
*
*/
type WidenStructure<T> = T extends string
? string
: never | T extends number
? number
: never | T extends bigint
? bigint
: never | T extends boolean
? boolean
: never | unknown extends T
? unknown
: never | T extends any[]
? T extends [infer Head, ...infer Tail]
? [WidenStructure<Head>, ...WidenStructure<Tail>]
: []
:
| never
| {
[K in keyof T]: T[K] extends Function ? T[K] : WidenStructure<T[K]>;
};
type A = WidenStructure<["a", "b"]> // [string, string]
declare const lambda: unique symbol;
/**
* Declares basic lambda function with an unique symbol
* to force other interfaces extending from this type
*/
interface Lambda<Args = unknown, Return = unknown> {
args: Args;
return: Return;
[lambda]: never;
}
/**
* Composes two Lambda type functions and returns a new lambda function
* JS-equivalent:
* const compose = (a,b) => (arg) => a(b(arg))
*
*/
interface Compose<
A extends Lambda<WidenStructure<Return<B>>>,
B extends Lambda<any, Args<A>>,
I extends Args<B> = Args<B>,
> extends Lambda {
args: I;
inner: Call<B, Args<this>>;
return: this["inner"] extends Args<A>
? Call<A, this["inner"]>
: never;
}
/**
* Gets return type value from a Lambda type function
*/
type Call<M extends Lambda, T extends Args<M>> = (M & {
args: T;
})["return"];
/**
* Extracts the argument from a lambda function
*/
type Args<M extends Lambda> = M["args"];
type Return<M extends Lambda> = M["return"];
// Test
interface UpperCase extends Lambda<string> {
return: Uppercase<Args<this>>;
}
interface LowerCase extends Lambda<string> {
return: Lowercase<Args<this>>;
}
type Test = Call<UpperCase, "asd">; // "ASD"
type ComposeTest = Call<Compose<LowerCase, UpperCase>, "asdasd">; // "asdasd"
它是如何工作的:
如果你与unknown // eg unknown & {} => {}
unknown 将被交集的其他部分替换。
因此,通过创建 Lambda 接口,我们可以通过this["args"]
访问 arguments 并用未知数“预填充”我们的大写。
当我们使用Call
类型时,我们将 UpperCase-Lambda 的参数与一些输入相交并替换该值。 现在通过访问 Lambdas 返回值,我们可以访问大写类型的正确值
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.