【问题标题】:Type-checking the dynamic value of an action creator parameter类型检查动作创建者参数的动态值
【发布时间】:2021-02-01 19:40:22
【问题描述】:

在我的 Redux 结构中,我有 2 个动作创建者 — setaddadd 中的有效负载类型应该是 User 对象或 Post 对象,而在 set 中它应该是 string | number | boolean |一个用户对象 |一个 Post 对象 |用户数组 |帖子数组。

type Payload = string | number | boolean | User | Post | User[] | Post[];

interface SetItem {
    type: string;
    name: string;
    payload: Payload;
}

interface Add {
    type: string;
    name: string;
    payload: User | Post;
}

export const set = (name: string, payload: Payload): SetItem => ({
    type: 'SET',
    name,
    payload,
});

export const add = (name: string, payload: User | Post): Add => ({
    type: 'ADD',
    name,
    payload,
});

在我的reducer中,我在Action接口中合并了两种类型。

type Payload = string | number | boolean | User | Post | User[] | Post[];

interface Action {
    type: string;
    name: string;
    payload: Payload | (User | Post);
}

function reducer(state: State, action: Action): State {
    if (action.type === 'SET') {
        let property: Payload = state[action.name];

        property = action.payload;

        return state;
    }

    if (action.type === 'ADD') {
        const property: (User | Post)[] = state[action.name];
        const payload: User | Post = action.payload;

        property.push(payload);

        return state;
    }

    return state;
}

您会注意到,在第二个if 语句中,我声明了一个payload 变量并将其类型设置为User | Post,但错误表明:

Payload 类型不能分配给User | Post 类型。

或者我输入检查初始状态的方式可能与错误有关。

interface State {
    [index: string]: User[] | Post[];
    users: User[];
    posts: Post[];
}

const state: State = {
    users: [],
    posts: [],
};

在对不同操作中具有不同类型的有效负载值进行类型检查时,我需要帮助。

【问题讨论】:

    标签: reactjs typescript redux


    【解决方案1】:

    您需要执行类型保护,因为此时action.payload 仍可能是string | number | boolean | User[] | Post[]。您可以通过定义两种不同的 Action 类型来做到这一点,通过检查 action.type 可以将其缩小到一种或另一种:

    interface SetAction {
        type: 'SET';
        name: string;
        payload: Payload;
    }
    
    interface AddAction {
        type: 'ADD';
        name: string;
        payload: User | Post;
    }
    
    type Action = SetAction | AddAction;
    
    function reducer(state: State, action: Action): State {
        if (action.type === 'SET') {
            // We DEFINITELY have a SetAction here
            let property: Payload = state[action.name];
    
            property = action.payload;
    
            return state;
        }
    
        if (action.type === 'ADD') {
            // We DEFINITELY have an AddAction here
            const property: (User | Post)[] = state[action.name];  // is this safe?
            const payload = action.payload;
    
            property.push(payload);
    
            return state;
        }
    
        return state;
    }
    

    Playground

    【讨论】:

    • 错误依然存在。此外,property 的类型应该是用户数组或帖子数组,因为从 http 响应返回的项目将根据数据添加到其中一个。所以我认为我对它所做的类型检查是安全的。
    • TypeScript Playground 没有出错。关于property,这是一个不同的问题。如果您想要所有这些保证,您还必须考虑如何键入 State 对象。
    • 我的错,我忘了在我的有效负载变量上删除User | Post。虽然错误仍然存​​在,但它现在表示Payload 类型的参数不可分配给User | Post 类型的参数。
    • 你是如何定义你的动作子类型的?仔细查看我的答案中的 SetAction 和 AddAction 类型。
    • 一旦你检查了 action.type,打字稿就会知道你是否有一个 SetAction 或一个 AddAction。如果这些类型中的每一个都正确定义了它们的有效负载属性,那么您也知道它们是什么。这是类型保护的基础。如果您需要复习,请阅读手册。
    猜你喜欢
    • 1970-01-01
    • 2021-01-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-21
    • 1970-01-01
    相关资源
    最近更新 更多