#reactjs #typescript
Вопрос:
У меня есть существующий проект React Javascript, который я переношу на Typescript.
Мой существующий код имеет действительно хороший однонаправленный поток, который я хотел бы сохранить при добавлении типов. В настоящее время это происходит следующим образом:
1. Component: FoobarListComponent -> useQueryFetchFoobars()
2. Hook: useQueryFetchFoobars() -> FoobarApi.list()
3. API: FoobarApi.list() -> axios.get("/api/v1/foobars")
Поскольку он написан на JS, часто неясно, каковы типы ответов конечных точек API. В приведенном выше примере нет ввода текста, поэтому разработчик понятия foobar
не имеет, как выглядит объект. Вот где я хотел бы использовать Typescript.
Я хотел бы ввести все полезные данные моего ответа API. Однако я бы предпочел, чтобы об этом знал только уровень API (# 3 в последовательности выше ^), потому что в настоящее время существует четкое разделение между Components -> Hooks -> APIs
. Если я делаю это на другом уровне, это кажется немного неправильным… Кроме того, я бы предпочел не экспортировать типы, потому что в настоящее время мои компоненты никогда не импортируются напрямую с уровня API.
Это пример того, что я бы предпочел не делать:
import React from "react";
import useQueryFoobars from "hooks/useQueryFoobars";
import { FoobarListResponseType } from "apis/foobar";
const SomeComponent = () => {
const { data } = useQueryFoobar<FoobarListResponseType | null>();
...
}
Серверная часть написана плохо, поэтому я не могу ожидать, что все объекты будут выглядеть одинаково при доступе к одному и тому же ресурсу. Под этим я подразумеваю, что иногда API-интерфейсы detail и list API возвращают объекты различной формы, например, так:
GET /api/v1/foobars
[
{ id: "f1", name: "Baz" },
{ id: "f2", name: "Lorem" },
]
GET /api/v1/foobar/f1
{ id: "f1", name: "Baz", email: "something@yahoo.com , address: "..." },
Поэтому я хотел бы иметь возможность вводить каждую конечную точку по отдельности.
Одно из решений, о котором я думал, заключалось в экспорте типов внутри файлов API. Однако не означает ли это, что Typescript должен будет вывести мой тип на 2 уровня ниже? API -> Hook -> Component?
- Приемлемо ли это в мире TS?
- Верно ли мое предположение, что TS сможет определить тип?
Или ожидается, что типы будут явно установлены на каждом уровне? Пожалуйста, дайте мне знать, если я ошибаюсь, я впервые использую TS.
Ответ №1:
Почему вы боитесь импортировать типы? Они практически не существуют во время выполнения и ничего не добавляют к результирующему размеру пакета.
В любом случае, typescript имеет довольно хороший вывод типа, не требуя явного ввода, но это также зависит от того, как вы настроили свой tsconfig.json
.
Следовательно, в некоторой степени возможно иметь типы только на уровне API, сохраняя при этом строгую типизацию в модулях, которые используют API. По большей части ваш пробег будет зависеть от вашей IDE и от того, включены ли вы allowJs
в tsconfig (если вы все еще смешиваете typescript с javascript).
Для вашего примера, если вы просто объявите FoobarApi.list()
как:
namespace FoobarApi {
export const list = () => axios.get<FoobarListResponseType>("/api/v1/foobars");
}
export default FoobarApi;
Тогда это вся информация о типе, необходимая typescript для определения типа data
свойства для ответа.
Комментарии:
1. Спасибо за быстрый ответ! Чтобы ответить на ваш вопрос: я не решаюсь импортировать типы, потому что 1) мне кажется, что я начну смешивать типы с файлами, которые когда-то были сосредоточены исключительно на чем-то одном 2) Я не уверен, где хранить мои типы.
src/types/api
?2. @bigpotato Я обычно храню их внутри файла, вызываемого
types.ts
в папке, в которой они используются. Затем я импортирую типы, используяimport type {TypeA, TypeB, etc...} from module/types
. В любом случае, я понимаю вашу нерешительность, но если вы используетеimport type
синтаксис, я думаю, это также может помочь прояснить, что эти импортные данные предназначены для информации о типе