sca*_*per 4 generics typescript
问题:
假设我有一个来自使用泛型的第三方库的接口
interface SomeInterface<T> {
...
}
Run Code Online (Sandbox Code Playgroud)
在我的代码中,我有一个实现该接口的实例
const someInstance; // type signature: SomeInterface<string>
Run Code Online (Sandbox Code Playgroud)
鉴于此实例,我将如何访问该实例的泛型类型参数 T 的类型(在此示例中,我将如何从中提取string类型someInstance)?我在运行时不需要它,我只需要它,以便我可以定义期望作为函数参数的类型:
function someFunction(someArg: ???) {...}
Run Code Online (Sandbox Code Playgroud)
基本上我希望能够做到这一点,但这是行不通的:
function someFunction(someArg: typeof T in someInstance) {...}
Run Code Online (Sandbox Code Playgroud)
具体用例:
我在这里的具体用例是我正在使用redux-act和redux-sagas包。Redux-act 提供了一个动作创建者工厂,它产生一个类型签名为的动作创建者ActionCreator<P, M>
// someActionCreator has type signature of ActionCreator<string, void>
const someActionCreator = createAction<string, number>(...);
Run Code Online (Sandbox Code Playgroud)
当这个动作创建者被调用通过时someActionCreator(payload: P, metadata: M),它会产生一个Action<P, M>.
// someAction has a type signature of Action<string, number>
const someAction = someActionCreator("foo", 1);
Run Code Online (Sandbox Code Playgroud)
在 redux sagas 中,我可以访问动作创建者实例(即someActionCreator),其中P和M定义了类型,但我无权访问动作本身。但是,处理程序函数期望将操作作为参数,例如
function* someEffectHandler(action: Action<string, void>) {...}
Run Code Online (Sandbox Code Playgroud)
由于打字稿知道的类型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>(...);
Run Code Online (Sandbox Code Playgroud)
type GetInnerType<S> = S extends SomeInterface<infer T> ? T : never
Run Code Online (Sandbox Code Playgroud)
用法:
type InnerType = GetInnerType<typeof someInstance>
Run Code Online (Sandbox Code Playgroud)
您可以尝试一下,然后可以从泛型类型中获取泛型参数。
// 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];
Run Code Online (Sandbox Code Playgroud)
我不能 100% 确定该解决方案是否实现了您所声明的减少样板代码的目标,但它确实提取了通用参数。一个优点也许是,如果您重构原始操作,则不必更改任何类型,无论您使用firstArg和sec,所有类型都将被正确推断