问题:
假设我有来自使用泛型的第三方库的界面
interface SomeInterface<T> {
...
}
在我的代码中,我有一个实现该接口的实例
const someInstance; // type signature: SomeInterface<string>
鉴于此实例,我将如何访问该实例的泛型类型参数T的类型(在此示例中,我如何从string
中提取someInstance
类型)?我不需要它用于运行时,我只需要它以便我可以定义期望作为函数中的参数的类型:
function someFunction(someArg: ???) {...}
基本上我希望能够做到这一点,这是行不通的:
function someFunction(someArg: typeof T in someInstance) {...}
具体用例:
我的具体用例是我使用redux-act
和redux-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
),其中P
和M
已定义类型,但我无法访问行动本身。但是,处理函数期望将操作作为参数,例如
function* someEffectHandler(action: Action<string, void>) {...}
由于Typescript知道P
上M
和someActionCreator
的类型是什么,我希望能够在someEffectHandler
的类型声明中访问它们。
我想要避免的是,当动作创建者应该能够给我输入类型参数时,必须为每个动作编写大量的样板。
//Trying to avoid this
type SomeActionPayload = string;
type SomeActionMetadata = number;
export type SomeAction = Action<SomeActionPayload, SomeActionMetadata>;
export const someActionCreator = createAction<SomeActionPayload, SomeActionMetadata>(...);
答案 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>