Вкажіть тип повернення у функції стрілки TypeScript


118

Я використовую React і Redux і маю типи дій, вказані як інтерфейси, щоб мої редуктори могли скористатися типовими типами об'єднань для поліпшення безпеки типу.

Отже, у мене є декларації типу, які виглядають приблизно так:

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' обробляється у функції (що може не бути проблемою, Я вважаю.)

Чи є поради щодо найкращого способу зробити це?


6
getTitle = ():string => 'State Lists'
— Вікас Бансал

Відповіді:


147

Спочатку розгляньте наступне позначення з початкового запитання:

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"'.

Також дивіться приклад ігрового майданчика .


Це саме те позначення, яке я шукав. На жаль, Visual Studio Code не підкреслює це синтаксисом таким чином, що відповідає моїм очікуванням, але компілятор, здається, це розуміє.
— Брайан Ханечак

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}; };

2
як би в цьому прикладі можна було використати дженерики? Скажімо, AddTodoActionCreator <T>
— Jannic Beck

1
Що UserEventтут?
— 1252748
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.