简体   繁体   English

TypeScript 类型获取约束的返回类型 Function 类型 Generics

[英]TypeScript Type Get Return Type of Constrained Function Type Generics

Basically, I am trying to find a way to use function types as generic types to find the return type of the function with the constraint that I choose.基本上,我试图找到一种使用 function 类型作为泛型类型的方法,以找到具有我选择的约束的 function 的返回类型。 However, I'm not sure if it's possible because I don't understand how generic function parameters work in conditional clauses.但是,我不确定这是否可行,因为我不了解通用 function 参数在条件子句中的工作方式。 Here is what I'm trying currently:这是我目前正在尝试的:

type FooFormatter = <S extends string>(input: S) => `foo-${S}`;

type StringFormatter = <S extends string>(input: S, ...args: never) => string;

type ComputeFormatter<Input extends string, T extends StringFormatter> =
    T extends (input: Input, ...args: never) => `${infer $Value}`
        ? $Value
        : never;

type foo = ComputeFormatter<"hey", FooFormatter>; // this is `foo-${string}` but I want "foo-hey"

TypeScript Playground Link TypeScript 游乐场链接

In ComputeFormatter I'm trying to check if I can somehow constrain the generic in T by overwriting the function's first parameter to the Input type.ComputeFormatter ,我试图检查是否可以通过将函数的第一个参数覆盖为Input类型来以某种方式限制T中的泛型。 Thanks for any help!谢谢你的帮助!

Short answer, there is an PR merged for TS4.7 for this feature.简短的回答,有一个针对此功能的 TS4.7 合并的PR Of particular relevance to your question...与您的问题特别相关......

type Box<T> = ReturnType<typeof makeBox<T>>;  // { value: T }

This is super close to a solution of #37181.这非常接近 #37181 的解决方案。 Will it will allow us to do...它会让我们做...

 return { value }; }; // Can we do it or something similar? Currently doesn't compile:( type MakeBox<T> = ReturnType<typeof makeBox<T>> // As it now allows us to do (no generics though) const stringMakeBox = makeBox<string>; type MakeBox = ReturnType<typeof stringMakeBox> // And even more relevant to support generics if we can now do: type MakeBox = ReturnType<typeof makeBox<string>>

Yes, you can indeed use that pattern to capture a generic return type of a generic function. This is something that previously wasn't possible.是的,您确实可以使用该模式来捕获通用 function 的通用返回类型。这在以前是不可能的。 I'll update the PR description to include an example.我将更新 PR 描述以包含示例。

Comment here在这里发表评论

I can't find anything on whether this works on type aliases for functions, or just works on runtime functions only (inferred with typeof ), but you can possibly just use the actual runtime implementations and use typeof as needed我找不到任何关于这是否适用于函数的类型别名,或者仅适用于运行时函数(用typeof推断)的任何信息,但您可以只使用实际的运行时实现并根据需要使用typeof

Here is this working on the nightly build , note that you'll still need a runtime implementation, whether or not it actually implements anything is up to you, it could be some mock function that doesn't return anything这是每晚构建的工作,请注意你仍然需要一个运行时实现,它是否实际实现任何东西取决于你,它可能是一些不返回任何东西的模拟 function

type FooFormatter = <S extends string>(input: S) => `foo-${S}`;

const FooFormatterImplementation: FooFormatter = {} as any; //mock implementation

type StringFormatter = <S extends string>(input: S, ...args: never) => string;

type foo = ReturnType<typeof FooFormatterImplementation<"hey">>
//  ^? `type foo = "foo-hey"`

My two-cents and more (More Post Script stuff)我的两分钱和更多(更多 Post Script 内容)

I highly recommend investigating some of the types they have over at type-fest , if you haven't already.我强烈建议您调查他们在type-fest上的一些类型,如果您还没有的话。 Especially尤其

Reading through the library, it looks like you've got a good sense of types, and I think you may actually be limited by the TS version of Deno.通读库,看起来你对类型有很好的感觉,我认为你实际上可能受到 Deno 的 TS 版本的限制。

There are a bunch of workarounds, but I'm not sure if they're really applicable in your usecase.有很多解决方法,但我不确定它们是否真的适用于您的用例。

Edit: Workaround with declaration merging and interfaces编辑:声明合并和接口的解决方法

This is not dependent upon TS4.7 Hooray!这不依赖于 TS4.7万岁!

type FooFormatter = <S extends string>(input: S) => `foo-${S}`;

type BarFormatter = <S extends string>(input: S) => `bar-${S}`

export interface Formatters {
    FooFormatter: FooFormatter,
    BarFormatter: BarFormatter
}
// then anyone wanting to add a custom formatter, has to modify and reexport the interface,
// this is similiarly done in @react-mui, using module augmentation
// https://www.typescriptlang.org/docs/handbook/declaration-merging.html

function takeInnerTest<T extends string, FmtKey extends keyof Formatters>(input: T, formatter: FmtKey)
{
    type formattersDiscriminated = {
        [K in keyof Formatters]: Formatters[K]
    }[FmtKey]
    const __mockFunction: formattersDiscriminated = ((...args: any[]) => undefined) as any
    const __mockReturn = __mockFunction(input)
    type String = ReturnType<typeof __mockFunction>
    type ReturnValue = Extract<typeof __mockReturn, String>
    return null! as ReturnValue
}

const foo3 = takeInnerTest("hey", "FooFormatter")
type foo3 = typeof foo3
//  ^?
const foo4 = takeInnerTest("hey", "BarFormatter")
type foo4 = typeof foo4
//  ^?

TS Playground TS游乐场

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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