Допустим, у меня есть приложение для списка дел. Я мог бы представить тип объектов, связанных с этими конечными точками, как:

type Todo = {
  id?: number,
  title: string,
  description: string
};

Теперь рассмотрим следующий код:

// @flow
type Todo = {
  id?: number,
  title: string,
  description: string
};
function patchTodo(todo: Todo) {}
const todo = {
  title: 'title'
};
patchTodo(todo);

Если я попытаюсь ввести todo вместо Todo, Flow вернет следующую ошибку:

15: patchTodo(todo);
     ^^^^^^^^^^^^^^^ function call
  9: function patchTodo(todo: Todo) {}
                              ^^^^ property `description`. Property not found in
 15: patchTodo(todo);
               ^^^^ object literal

description является обязательным ключом для Todo, хотя нам не нужно отправлять его как часть нашего запроса PATCH, чтобы обновить заголовок. Как мы можем ввести patchTodo(todo), чтобы позволить нам отправлять частичные объекты?

Один из подходов состоит в том, чтобы поддерживать второй тип со всеми необязательными аргументами:

type PatchTodo = {
  id?: number,
  title?: string,
  description?: string
};

Проблема в том, что этот подход не очень СУХОЙ. Каждый раз, когда мы добавляем, обновляем или удаляем свойство этого объекта, мы должны делать это в двух местах. В идеале мы хотим поддерживать только один тип.

Введите $Shape‹T›

$Shape<T> — это служебный тип, который я нашел, читая этот пост. Он имеет следующие свойства:

Тип $Shape‹T› имеет два отличия от T: объекты этого типа не могут содержать свойства, не описанные в T, и могут не содержать требуемых свойств. типа Т.

Это означает, что мы можем проверять запросы PATCH, используя наш исходный тип Todo:

// @flow
function patchTodo(todo: $Shape<Todo>) {}
const todo = {
  title: 'title'
};
const malformedTodo = {
  title: 'title',
  baz: 'baz'
};
patchTodo(todo);
patchTodo(malformedTodo);

patchTodo(malformedTodo) выдаст нам следующую ошибку:

21: patchTodo(malformedTodo);
     ^^^^^^^^^^^^^^^^^^^^^^^^ function call
 21: patchTodo(malformedTodo);
               ^^^^^^^^^^^^^ property `baz` of object literal. Property not found in
  9: function patchTodo(todo: $Shape<Todo>) {}
                                     ^^^^ object type

Теперь при каждом изменении нашегоTodoтипа проверкаPATCHтипа будет по-прежнему искать эти обновленные свойства без необходимости поддерживать два типа!