等效于多个嵌套泛型的函数撰写的打字稿

时间:2020-01-23 08:58:52

标签: typescript generics

有时候我会在一种类型上做很多操作,以便创建一个新的类型,即:

type Complex = Omit<Merge<Interface1, {modifiedField: false}>, 'omitted field'>

是否存在等效的功能composepipe功能,因此创建这样的类型将更具可读性,即:

type Complex = Pipe<Interface1, 
   Merge<{modified: false}>,
   Omit<'omitted field'>
>

1 个答案:

答案 0 :(得分:1)

不,该语言没有这种工作所需的那种高阶类型操纵。我能想象的最接近的是从类型级别下降到值级别,滥用最近的screenshot of tooltip window,然后再返回到类型级别。它不是很漂亮,您最终会得到一些无用的运行时代码来启动。

这就是我的意思。我假设您具有以下定义:

interface Interface1 {
    a: string;
    "omitted field": boolean;
}
type Merge<T, U> = T & U;
type ManualComplex = Omit<Merge<Interface1, { modifiedField: false }>, 'omitted field'>
/* type ManualComplex = {
    a: string;
    modifiedField: false;
} */

然后是我正在谈论的值的跳跃:

declare const CurriedOmit: <K extends PropertyKey>() => <T>(t: T) => Omit<T, K>;
declare const CurriedMerge: <U>() => <T>(t: T) => Merge<T, U>;
declare const Id: <T>() => T

我假装有一个咖喱OmitMerge,还有一个Id。然后,我们可以假设有一个pipe()函数按顺序应用这些函数:

// there may be some variadic pipe but for now let's do this:
declare const pipe: {
    <A>(a: A): A;
    <A, B>(a: A, b: (a: A) => B): B;
    <A, B, C>(a: A, b: (a: A) => B, c: (b: B) => C): C;
    <A, B, C, D>(a: A, b: (a: A) => B, c: (b: B) => C, d: (c: C) => D): D;
}

最后,我写了一些实际的运行时代码,使编译器无法评估您想要的类型,尽管在运行时该代码会短路到true(这很好,因为如果实际上调用了非存在的pipe()函数,您会遇到一些令人讨厌的运行时错误):

const complex = (true as false) || pipe(
    Id<Interface1>(),
    CurriedMerge<{ modifiedField: false }>(),
    CurriedOmit<'omitted field'>()
);

现在,编译器认为它具有值complex,我们可以将Complex作为typeof complex来获得:

type Complex = typeof complex;
/* type Complex = {
    a: string;
    modifiedField: false;
} */

是的,它与ManualComplex的类型相同。 worth值得吗?不,??,我尽力了。我绝对会坚持使用您开始使用的非管道版本。祝你好运!

support for higher order function inference from generic functions

相关问题