首页 文章

在TypeScript箭头函数中指定返回类型

提问于
浏览
59

我正在使用React和Redux并将操作类型指定为接口,以便我的reducer可以利用标记的联合类型来提高类型安全性 .

所以,我的类型声明看起来像这样:

interface AddTodoAction {
    type: "ADD_TODO",
    text: string
};

interface DeleteTodoAction {
    type: "DELETE_TODO",
    id: number
}

type TodoAction = AddTodoAction | DeleteTodoAction

我想制作创建这些动作的辅助函数,我倾向于使用箭头函数 . 如果我写这个:

export const addTodo1 = (text: string) => ({
    type: "ADD_TODO",
    text
});

编译器无法提供任何帮助以确保它是有效的 AddTodoAction ,因为未明确指定返回类型 . 我可以通过这样做明确指定返回类型:

export const addTodo2: (text: string) => AddTodoAction = (text: string) => ({
    type: "ADD_TODO",
    text
})

但是这需要两次指定我的函数参数,所以它的冗长和难以阅读 .

有没有办法在使用箭头符号时明确指定返回类型?

我想过尝试这个:

export const addTodo3 = (text: string) => <AddTodoAction>({
    type: "ADD_TODO",
    text
})

在这种情况下,编译器现在将返回类型推断为 AddTodoAction 但它确认我返回的对象具有所有适当的字段 .

我可以通过切换到不同的函数语法来解决这个问题:

export const addTodo4 = function(text: string): AddTodoAction {
    return {
        type: "ADD_TODO",
        text
    }
}

export function addTodo5(text: string): AddTodoAction {
    return {
        type: "ADD_TODO",
        text
    }
}

这些方法中的任何一个都会导致编译器使用正确的返回类型并强制我已经适当地设置了所有字段,但它们也更加冗长,并且它们改变了在函数中处理“ this ”的方式(这可能不是问题, 我想 . )

关于最好的方法有什么建议吗?

2 回答

  • 79

    首先,请考虑原始问题中的以下符号:

    export const addTodo3 = (text: string) => <AddTodoAction>({
        type: "ADD_TODO",
        text
    })
    

    使用此表示法,将返回的对象类型转换为 AddTodoAction 类型 . 但是,函数声明的返回类型仍未定义(并且编译器将隐式假设 any 为返回类型) .

    请改用以下符号:

    export const addTodo3 = (text: string): AddTodoAction => ({
        type: "ADD_TODO",
        text: text
    })
    

    在这种情况下,省略必需属性将产生预期的编译器错误 . 例如,省略 text 属性将生成以下(所需)错误:

    Type '{ type: "ADD_TODO"; }' is not assignable to type 'TodoAction'.
      Type '{ type: "ADD_TODO"; }' is not assignable to type 'DeleteTodoAction'.
        Types of property 'type' are incompatible.
          Type '"ADD_TODO"' is not assignable to type '"DELETE_TODO"'.
    

    另见playground example .

  • 1

    我认为你最好的办法是为你的函数创建一个具有正确类型的接口,然后你只需要指定该类型,而不是所有嵌套类型的接口:

    interface AddTodoAction {
        type: "ADD_TODO",
        text: string
    };
    
    interface AddTodoActionCreator {
        (text: string): AddTodoAction;
    };
    
    export const addTodo: AddTodoActionCreator = (text) => ({
        type: "ADD_TODO",
        text
    });
    

    更新:如何使用类型执行此操作

    export interface GeneralAction<T> {
        type: string;
        payload: T;
    }
    
    export interface GeneralActionCreator<T> {
        (payload: T): GeneralAction<T>;
    }
    
    export const SAVE_EVENT = 'SAVE_EVENT';
    
    export const SaveEvent: GeneralActionCreator<UserEvent> = (payload) => { return {type: SAVE_EVENT, payload}; };
    

相关问题