【问题标题】:Typescript: Get type of an instance's genericTypescript:获取实例泛型的类型
【发布时间】:2018-12-08 15:00:56
【问题描述】:

问题:

假设我有一个使用泛型的第三方库的接口

interface SomeInterface<T> {
    ...
}

在我的代码中,我有一个实现该接口的实例

const someInstance; // type signature: SomeInterface<string>

鉴于此实例,我将如何访问该实例的泛型类型参数 T 的类型(在此示例中,我如何能够从 someInstance 中提取 string 类型)?我在运行时不需要它,我只需要它以便我可以定义期望的类型作为函数中的参数:

function someFunction(someArg: ???) {...}

基本上我希望能够做到这一点,这是行不通的:

function someFunction(someArg: typeof T in someInstance) {...}

具体用例:

我在这里的具体用例是我使用redux-actredux-sagas 包。 Redux-act 提供了一个动作创建者工厂,它产生一个类型签名为ActionCreator&lt;P, M&gt;的动作创建者

// someActionCreator has type signature of ActionCreator<string, void>
const someActionCreator = createAction<string, number>(...); 

当通过someActionCreator(payload: P, metadata: M) 调用此动作创建者时,它会生成Action&lt;P, M&gt;

// someAction has a type signature of Action<string, number>
const someAction = someActionCreator("foo", 1);

在 redux sagas 中,我可以访问动作创建者实例(即 someActionCreator),其中 PM 已定义类型,但我无法访问动作本身。但是,处理函数期望操作作为参数,例如

function* someEffectHandler(action: Action<string, void>) {...}

由于 Typescript 知道 PMsomeActionCreator 上的类型,我希望能够在 someEffectHandler 的类型声明中访问它们。 当动作创建者应该能够为我提供类型化参数时,我试图避免为每个动作编写大量样板。

//Trying to avoid this
type SomeActionPayload = string;
type SomeActionMetadata = number;
export type SomeAction = Action<SomeActionPayload, SomeActionMetadata>;
export const someActionCreator = createAction<SomeActionPayload, SomeActionMetadata>(...);

【问题讨论】:

  • 并非总是可行,但您可以深入到类型为 T 的属性并执行 typeof 该属性。
  • @unional 不幸的是,因为实例还没有 T 的值(只是它期望的类型),实例上没有属性可以调用 typeof on。

标签: typescript generics


【解决方案1】:
type GetInnerType<S> = S extends SomeInterface<infer T> ? T : never

用法:

type InnerType = GetInnerType<typeof someInstance>

【讨论】:

  • any 类型是否可以泛型?喜欢S extends any&lt;infer T&gt;
  • @fregante 在这种情况下解析 T 没有用,因为您不知道它可以用来做什么。你不知道它是不是类型——例如——一个属性或返回或输入,所以你不能用它做任何事情。
【解决方案2】:

您可以尝试一下,您可以从泛型类型中获取泛型参数。

// Helper method, this will declare it returns a tuple of the two generic argument types, but at runtime it will just return an empty array. Used only to help with type inference.

function inferHelper<P, M>(creator: (p: P, m:M) => Action<P,M>) : [P, M]{
    return <any>[];
}
// Dummy variable, will be typed as [string, number] in your example, but will not actually hold anything at runtime
let helper = inferHelper(someActionCreator); // Dummy variable should not be used
// we get the type of the first tuple element, which we can then use 
type firstArg = typeof helper[0];
// and the second
type secondArg = typeof helper[1];

我不能 100% 确定此解决方案是否能实现您声明的减少样板代码的目标,但它确实提取了通用参数。一个优点可能是,如果您重构原始操作,您不必更改任何类型,无论您使用 firstArg 和 sec,所有类型都将被正确推断

【讨论】:

    【解决方案3】:

    您可以使类型如下所示。不确定这是否是您要查找的内容。

    // define the function
    function someFunction<U extends SomeInterface<T>>(someArg: T) {...}
    
    // call the function
    someFunction<typeof someInstance>(someArg) {
        // someArg will have type string
    }
    

    【讨论】:

      猜你喜欢
      • 2019-01-20
      • 2020-06-11
      • 2016-04-05
      • 2021-03-20
      • 1970-01-01
      • 2021-07-10
      • 2016-03-14
      • 2021-10-07
      • 1970-01-01
      相关资源
      最近更新 更多