簡體   English   中英

TypeScript 如何為泛型 function 創建泛型類型別名?

[英]TypeScript how to create a generic type alias for a generic function?

給定一個類型化的通用 function,我想為該 function 創建一個通用別名,但似乎我不能。 換句話說,這不起作用:

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

我真正想做的是在別人的庫中獲取 function 的類型,然后圍繞它構建一個接口。 例如:

import { useState } from "react"

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

如果不自己重新創建復雜類型的 function 簽名,這是否可能?

TypeScript 中有兩種不同風格的 generics:泛型函數和泛型類型……看起來您希望編譯器為您將一種轉換為另一種,但不直接支持。


要清楚:

泛型類型具有需要指定的類型參數,然后才能將它們用作特定類型。 例如:

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 function 接受一個string並返回一個string[] 它不能用作接受number並返回number[]的 function 。


另一方面,泛型函數具有特定類型,可以像任何可能的類型參數替換一樣。 泛型 function 類型的值在使用時仍然是泛型的。 類型參數附加到調用簽名:

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

這里, GenFunc是一個特定類型,指的是通用 function。 genF function 在被調用時仍然是通用的。

泛型函數(包括泛型構造函數)可以被認為是泛型值,而不是泛型類型。


這兩種 generics 是相互關聯的,但 TypeScript 類型系統的表達力不足以談論它們之間的關系。 在其他一些語言中,您可能可以根據另一種語言來定義一個,例如

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

或者

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

但在 TypeScript 你不能。 也許如果我們得到microsoft/TypeScript#1213中要求的更高種類的類型......但不是現在。 所以在類型系統中直接GenType GenFunc不可能的。


有一些邪惡的可怕方法可以強制編譯器根據GenFunc GenType 我所知道的方法利用了通用 class 屬性初始化和一些在 TypeScript 3.4 中引入的通用函數的高階類型推斷 當我實際上沒有任何值時,我讓編譯器認為它正在計算值,然后獲取這些假裝值之一的類型:

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

您可以驗證GenType2<T> GenType<T>類型相同,如果您將GenFunc更改為具有一個類型參數的任何通用 function , GenType2<T>將相應更改。

但我不知道我想推薦任何人實際使用這種方法。 而且它並沒有真正縮放或組合; 如果您有一個 object 在一個類型參數中充滿泛型函數,並且您想將其轉換為 object 充滿具有指定類型參數的特定函數,則無法使用此方法從類型系統中獲取它而無需執行一次對於每個 object 屬性。


無論如何,希望有所幫助; 祝你好運!

Playground 代碼鏈接

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM