【问题标题】:Omit return type from a function type?从函数类型中省略返回类型?
【发布时间】:2021-05-25 04:21:16
【问题描述】:

是否可以从具有相同参数和泛型但没有返回类型的现有打字稿函数创建新的函数类型?

示例:

我正在尝试从ReturnSame 函数创建类型ReturnNothing,而无需手动定义它。

type ReturnSame = <T extends string>(a: T) => T
type ReturnNothing = <T extends string>(a: T) => void

尝试:

function returnSame<T extends string>(a: T): T {
  return a;
}

// Attempt 1: Does not work. Generics is not following to new type.
const returnNothing1 = (...params: Parameters<typeof returnSame>) => {
  console.log(params);
};

// Attempt 2: Does not work. Return type is forced.
const returnNothing2: typeof returnSame = (...params) => {
  console.log(params);
};

// Attempt 3: Does not work. OmitReturn is a made up Typescript utility.
const returnNothing3: OmitReturn<typeof returnSame> = (...params) => {
  console.log(params);
};

// Usage
const same = returnSame<"a">("a");
const nothing1 = returnNothing1<"b">("b");

【问题讨论】:

    标签: typescript generics typescript-typings typescript-generics


    【解决方案1】:

    目前无法在类型级别自动纯粹执行此操作。含义:您不能采用像ReturnSame 这样的泛型函数类型并以不会立即插入unknown(或其泛型约束)的方式获取其参数,例如@987654326 @。这样做可能需要 TypeScript 目前不直接支持的更高种类的类型(有关功能请求,请参阅 microsoft/TypeScript#1213)。

    可以完全放弃并手动写出returnNothing() 作为通用函数,但您不想这样做。

    如果可以接受下拉到值级别,通过将returnSame() 传递给函数,您可以利用 TypeScript 3.4 中引入的higher order type inference from generic functions

    function makeNothingReturner<A extends any[]>(fn: (...a: A) => any): (...a: A) => void {
      return (...a) => void fn(...a);
    }
    
    const returnNothing = makeNothingReturner(returnSame);
    

    这里makeNothingReturner() 接受一个(可能是通用的)函数并返回另一个具有相同参数的函数void 返回类型。这个看起来的类型签名非常像你在你的类型级代码中所做的,所以它不会做同样的事情并且returnNothing是@987654333类型可能会令人惊讶@。但是看哪,IntelliSense 显示了这一点:

    // const returnNothing: <T extends string>(a: T) => void
    

    因此您可以根据需要使用它,通过使用指定的类型参数调用:

    const nothing = returnNothing<"b">("b"); // works
    

    Playground link to code

    【讨论】:

      【解决方案2】:

      除了@jcalz 所说的:在类型级别上是部分可能的。 (Playground link)

      type GenFN<S, T> = <AS extends S>(a: AS) => T
      
      
      type VoidFN<G extends GenFN<any, any>> =
        G extends GenFN<infer S, any>
          ? GenFN<S, void>
          : never
      
      
      type ThisWorks = VoidFN<GenFN<1, 2>>
      
      
      type ThisDoesNotWork = VoidFN<<AS extends 1>(a: AS) => 2>
      

      但这将要求您在任何地方都使用帮助器 GenFN,而不是像 &lt;AS extends 1&gt;(a: AS) =&gt; 2 这样的直接定义,从而使 VoidFN 与您的(当前和未来)代码库和第三方库的部分不兼容。

      另一个风险:如果您的代码库变大并且类型定义深度嵌套,我不确定 TS 是否可能会“忘记”/“丢弃”特定类型扩展 GenFN 的信息。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-10-19
        • 2021-02-05
        • 1970-01-01
        • 2012-09-21
        • 2019-05-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多