TypeScript 如何为泛型函数创建泛型类型别名? [英] TypeScript how to create a generic type alias for a generic function?

查看:43
本文介绍了TypeScript 如何为泛型函数创建泛型类型别名?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给定一个类型化的泛型函数,我想为该函数创建一个泛型别名,但似乎我不能.换句话说,这不起作用:

Given a typed generic function, I want to create a generic alias for that function, but it seems I can't. In other words, this doesn't work:

// foo.tsx
function foo<T>(arg: T): T {
  return arg
}

type FooT = typeof foo  // works, but alias isn't generic: <T>(arg: T) => T
type FooParametersT = Parameters<typeof foo>  // sure: [unknown]
type FooReturnT = ReturnType<typeof foo>  // no problem: unknown

type GFooT<T,> = typeof foo<T,>  // yikes
type GFooParametersT<T,> = Parameters<typeof foo<T,>>  // nope
type GFooReturnT<T,> = ReturnType<typeof foo<T,>>  // fails

我真正想做的是在别人的库中获取一个函数的类型,然后围绕它构建一个接口.例如:

What I'm really trying to do is grab the type of a function in someone else's library and then build an interface around it. For example:

import { useState } from "react"

type UseStateFnT<T,> = typeof useState<T>
const wrapUseState: (toWrap: UseStateFnT<T,>) => UseStateFnT<T,> = …

这是否可能不重新创建复杂类型的函数签名自己?

Is this possible without recreating the complex typed function signature myself?

推荐答案

TypeScript 中有两种不同风格的泛型:泛型 functions 和泛型 types...看起来您希望编译器为您将一个转换为另一个,但不直接支持.

There are two different flavors of generics in TypeScript: generic functions, and generic types... and it looks like you want the compiler to transform one into the other for you, which isn't directly supported.

要清楚:

通用类型具有类型参数,需要先指定这些参数,然后才能将它们用作特定类型.例如:

Generic types have type parameters that need to be specified before you can use them as a specific type. For example:

type GenType<T> = (x: T) => T[];
declare const oops: GenType; // error
declare const genT: GenType<string>; // okay
const strArr = genT("hello"); // string[];
const numArr = genT(123); // error!

这里,GenType 是一个泛型类型.您需要指定类型参数以将其用作值的类型,然后生成的类型不再是通用的.genT 函数接受一个 string 并返回一个 string[].它不能用作接受 number 并返回 number[] 的函数.

Here, GenType is a generic type. You need to specify the type parameter to use it as the type of a value, and then the resulting type is no longer generic. The genT function takes a string and returns a string[]. It cannot be used as a function that takes a number and returns a number[].

泛型函数,另一方面,有一个特定的类型,可以像对其类型参数的任何可能的替换一样起作用.泛型函数类型的值在使用时仍然是泛型的.类型参数附加到调用签名:

Generic functions, on the other hand, have a specific type that can act like any possible substitution of its type parameters. The value of a generic function type is still generic when you use it. The type parameter is attached to the call signature:

type GenFunc = <T>(x: T) => T[];
declare const genF: GenFunc;
const strArr = genF("hello"); // strArr: string[];
const numArr = genF(123); // numArr: number[];

这里,GenFunc 是指泛型函数的特定类型.genF 函数在调用时仍然是通用的.

Here, GenFunc is a specific type referring to a generic function. The genF function is still generic when it is called.

泛型函数(包括泛型构造函数)可以被认为是泛型值,与泛型类型相反.

Generic functions (including generic constructor functions) can be thought of as generic values, as opposed to generic types.

这两种泛型彼此相关,但 TypeScript 类型系统的表达能力不足以谈论它们之间的关系.在其他一些语言中,您可能可以根据另一种语言来定义一个,例如

These two flavors of generics are related to each other but the TypeScript type system isn't expressive enough to talk about how they are related. In some other language, you might be able to define one in terms of the other like

type GenFunc = forall T, GenType<T>; // not TS, error

type GenType<T> = instantiate GenFunc with T; // not TS, error

但在 TypeScript 中你不能.也许如果我们按照 microsoft/TypeScript#1213 中的要求获得更高级的类型...但不是现在.因此,在类型系统中以编程方式将 GenFunc 直接转换为 GenType 是不可能的.

but in TypeScript you can't. Maybe if we ever get higher kinded types as requested in microsoft/TypeScript#1213... but not now. So it is not directly possible to turn GenFunc into GenType programmatically in the type system.

根据GenFunc 强制编译器计算GenType 有一些邪恶的可怕方法.我所知道的方法是使用泛型类属性初始化和一些 泛型函数的高阶类型推断 在 TypeScript 3.4 中引入.当我实际上没有任何值时,我让编译器认为它正在计算值,然后获取这些假装值之一的类型:

There are evil awful ways to coerce the compiler to calculate GenType in terms of GenFunc. The way I know of makes use of generic class property initialization and some higher order type inference for generic functions introduced in TypeScript 3.4. I'm making the compiler think it's calculating values when I don't actually have any, and then getting the type of one of these pretend values:

class GenTypeMaker<T> {
    getGenType!: <A extends any[], R>(cb: (...a: A) => R) => () => (...a: A) => R;
    genType = this.getGenType(null! as GenFunc)<T>()
}
type GenType2<T> = GenTypeMaker<T>['genType']
// type GenType2<T> = (x: T) => T[]

你可以验证GenType2GenType是同一个类型,如果你把GenFunc改成任何泛型一个类型参数的函数,GenType2 会相应改变.

You can verify that GenType2<T> is the same type as GenType<T>, and if you change GenFunc into any generic function with one type parameter, GenType2<T> will change accordingly.

但我不知道我想推荐任何人实际使用这种方法.它并没有真正扩展或组合;如果您在一个类型参数中有一个充满泛型函数的对象,并且您想将其转换为一个充满具有指定类型参数的特定函数的对象,则无法使用此方法从类型系统中获取它而不做一次对于每个对象属性.

But I don't know I'd want to recommend anyone actually use this method. And it doesn't really scale or compose; if you have an object full of generic functions in one type parameter and you want to transform it to an object full of specific functions with a specified type parameter, there's no way to use this method to get it from the type system without doing it once for each object property.

无论如何,希望有所帮助;祝你好运!

Anyway, hope that helps; good luck!

游乐场链接代码

这篇关于TypeScript 如何为泛型函数创建泛型类型别名?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆