打字稿:获取实例的类型通用

时间:2018-01-10 05:34:51

标签: typescript generics

问题:

假设我有来自使用泛型的第三方库的界面

interface SomeInterface<T> {
    ...
}

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

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

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

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

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

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

具体用例:

我的具体用例是我使用redux-actredux-sagas个软件包。 Redux-act提供了一个动作创建工厂,可以生成类型签名为ActionCreator<P, M>

的动作创建者
// someActionCreator has type signature of ActionCreator<string, void>
const someActionCreator = createAction<string, number>(...); 

通过someActionCreator(payload: P, metadata: M)调用此动作创建者时,会生成Action<P, M>

// 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>(...);

3 个答案:

答案 0 :(得分:0)

你可以玩一下,你可以从泛型类型中获取泛型参数。

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

,所有类型都将被正确推断

答案 1 :(得分:0)

您可以使类型像下面那样工作。不确定这是否是您想要的。

// define the function
function someFunction<U extends SomeInterface<T>>(someArg: T) {...}

// call the function
someFunction<typeof someInstance>(someArg) {
    // someArg will have type string
}

答案 2 :(得分:0)

type GetInnerType<S> = S extends SomeInterface<infer T> ? T : never

用法:

type InnerType = GetInnerType<typeof someInstance>