为什么TypeScript强迫我为函数签名中键入为undefined的参数显式传递undefined?

时间:2019-05-25 16:03:36

标签: typescript redux

我是一名初级开发人员,需要帮助。我已经尝试过搜索问题,但是我很难以正确的方式来表述它。如果问题引起误解,请提前抱歉。

有人可以帮我理解为什么当我在函数签名中将参数键入为undefined时,TypeScript强迫我将undefined作为参数传递给函数吗?

这就是我想要做的。我想创建一个返回动作创建者函数的函数,然后该函数返回动作对象:

interface IAction<T, P> {
    type: T;
    payload?: P;
}

const createActionCreator = <T extends string, P = undefined>(type: T) => (payload: P): IAction<T, P> => ({
    type,
    payload,
});

const THIS_IS_MY_ACTION_TYPE = '@PREFIXED/THIS_IS_MY_ACTION_TYPE';

const createTestAction1 = createActionCreator<typeof THIS_IS_MY_ACTION_TYPE, string>(THIS_IS_MY_ACTION_TYPE);

const createTestAction2 = createActionCreator<typeof THIS_IS_MY_ACTION_TYPE>(THIS_IS_MY_ACTION_TYPE);

const testAction1 = createTestAction1('some string');
// works fine

const testAction2 = createTestAction2();
// TypeScript complains that an argument was expected

当我调用同时提供createActionCreatorT类型的P时,TypeScript强制我使用与createTestAction1类型匹配的参数来调用P。这就是我的期望。

当我在不提供createActionCreator的情况下调用P 时,或者即使我显式提供了P的{​​{1}},TypeScript也会强制我执行以下操作:以undefined作为参数调用createTestAction2。我希望能够不带参数地调用它。

如果有人可以帮助我理解它为何如此工作以及如何解决它,我将不胜感激。预先感谢。

2 个答案:

答案 0 :(得分:0)

函数(payload: P) => {..}有一个参数,因此即使参数类型为undefined,Typescript也需要一个参数。尝试使参数成为可选参数(使用?),然后从类型参数= undefined中删除默认的<P>类型。

const createActionCreator = <T extends string, P>(type: T) =>
//                                             ^ type `P` is required
    (payload?: P): IAction<T, P> => ({
    //      ^ parameter `payload` is optional
        type,
        payload, // if not provided, will be the value `undefined`
    });

答案 1 :(得分:0)

通过函数签名重载和第一次调用中的payloadRequired参数,我能够实现我想要的结果,以确定是否返回带有或不带有有效负载参数的内部函数:

export interface IAction<T extends IActionConstant, P = undefined> {
    type: T;
    payload?: P;
}

export function createActionCreator<T extends IActionConstant, P = 'Please provide a type definition for the payload'>(
    type: T,
    config: { withPayload: true }
): (payload: P) => IAction<T, P>;
export function createActionCreator<T extends IActionConstant>(
    type: T,
    config: { withPayload: false }
): () => IAction<T>;
export function createActionCreator<T extends IActionConstant, P>(type: T, config: { withPayload: boolean }) {
    if (config.withPayload) {
        return function createAction(payload: P) {
            return {
                type,
                payload,
            };
        };
    }
    return function createAction() {
        return {
            type,
        };
    };
}