[英]TypeScript use generic function parameter in curry function
我正在嘗試創建一個 function 來生成我的 redux 動作創建者。
假設我們的操作有以下類型:
export type DeleteAction = {
type: typeof BLAH_DELETE;
payload: {
id: string;
};
};
export type EditAction = {
type: typeof BLAH_EDIT;
payload: {
id: string;
name: string;
};
};
export MyAction = DeleteAction | EditAction
現在在動作文件中,我想以這種方式創建我的動作:
export const deleteBlah = makeActionCreator<MyAction>('BLAH_DELETE');
// Expected Behaviour
deleteBlah({ id: '' }) // Correct
deleteBlah({ id: '', name: '' }) // Error
export const editBlah = makeActionCreator<MyAction>('BLAH_EDIT');
// Expected Behaviour
editBlah({ id: '', name: '' }) // Correct
editBlah({ id: '' }) // Error
這是makeActionCreator
function:
export const makeActionCreator = <A extends { type: string; payload: any }>(type: A['type']) => (
payload: ActionPayload<ExtractAction<A, A['type']>>,
) => ({
type,
payload,
});
type ExtractAction<A, T> = A extends { type: T } ? A : never;
type ActionPayload<T extends { payload: any }> = Pick<T['payload'], keyof T['payload']>;
問題是我不知道如何將操作文件中提供的操作類型傳遞給ExtractAction<A, A['type']>
因此,有效負載對於A
的所有可能選項始終有效。
最終,我有一些想法可以將您的想法付諸實踐。 以下是幾個步驟:
payload
屬性的類型:type ValueType<T, K> = K extends keyof T ? T[K] : never;
type ExtractPayload<A, T> = A extends { type: T, payload: infer R } ? R : never;
Curry
function 接收動作作為參數:type Curry<A> = <T extends ValueType<A, 'type'>>(arg: T) => (payload: ExtractPayload<A, T>) => {
type: T
payload: ExtractPayload<A, T>
};
makeActionCreator<MyAction>()
這有點煩人:export const makeActionCreator = <A>(): Curry<A> => action => payload => ({
type: action,
payload,
})
// Testing
const deleteBlah = makeActionCreator<MyAction>()('BLAH_DELETE');
deleteBlah({ id: '' }) // Correct
deleteBlah({ id: '', name: '' }) // Error
另一種解決方案
另一種選擇,您將保留您的 function 而不創建更多咖喱級別,但您必須再傳遞一個輸入參數,如下所示:
type Curry1<A, T> = (payload: ExtractPayload<A, T>) => {
type: T
payload: ExtractPayload<A, T>
};
// The function is the same but have type T as new parameter
export const makeActionCreator = <A, T>(action: T): Curry1<A, T> => payload => ({
type: action,
payload,
})
// Testing, it's a bit odd as specify 'BLAH_DELETE' twice
const deleteBlah = makeActionCreator<MyAction, 'BLAH_DELETE'>('BLAH_DELETE');
deleteBlah({ id: '' }) // Correct
deleteBlah({ id: '', name: '' }) // Error
type Some<U, I> = (U extends I ? true : false) extends false ? false : true;
function makeCreator<T extends MyAction["type"]>(type: T) {
return function <P>(
p: { type: T; payload: P } extends MyAction
? Some<MyAction, { type: T; payload: P }> extends true
? P
: never
: never
): MyAction {
return null as any;
};
}
代碼
{ type: T; payload: P } extends MyAction
? OneOf<MyAction, { type: T; payload: P }> extends true
? P
: never
: never`
斷言您提供的參數正是根據給定type
的有效負載類型
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.