TypeScript 类型获取受约束函数类型泛型的返回类型

问题描述 投票:0回答:1

基本上,我试图找到一种将函数类型用作泛型类型的方法,以找到具有我选择的约束的函数的返回类型。但是,我不确定这是否可能,因为我不明白通用函数参数在条件子句中如何工作。这是我目前正在尝试的:

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 链接

ComputeFormatter
中,我试图检查是否可以通过将函数的第一个参数覆盖为
T
类型来限制
Input
中的泛型。感谢您的帮助!

typescript typescript-generics
1个回答
3
投票

简短的回答,针对此功能,为 TS4.7 合并了一个 PR。与您的问题特别相关...

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

这非常接近#37181 的解决方案。它会让我们做...

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>> 

是的,您确实可以使用该模式来捕获泛型函数的泛型返回类型。这是以前不可能的事情。我将更新 PR 描述以包含示例。

在这里评论

我找不到任何关于这是否适用于函数的类型别名,或者仅适用于运行时函数(用

typeof
推断)的信息,但您可能只使用实际的运行时实现并根据需要使用
typeof

这是在夜间构建上进行的工作,请注意,您仍然需要一个运行时实现,无论它是否实际实现任何内容都取决于您,它可能是一些不返回任何内容的模拟函数

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"`

我的两分钱和更多(更多后脚本的东西)

我强烈建议您调查一下他们在

type-fest
拥有的一些类型(如果您还没有的话)。特别是

通读该库,看起来您对类型有很好的了解,我认为您实际上可能受到 TS 版本的 Deno 的限制。

有很多解决方法,但我不确定它们是否真的适用于您的用例。

编辑:声明合并和接口的解决方法

这不依赖于 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游乐场

© www.soinside.com 2019 - 2024. All rights reserved.