繁体   English   中英

有没有办法将泛型类型参数限制为泛型类型?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM