У меня есть компонент Vue3, который выполняет некоторые запросы GraphQL. Он возвращает большой блок JSON, и я вычисляю, чтобы получить из него нужное значение. Я хочу передать это значение дочернему компоненту в качестве реквизита.
Однако в дочернем компоненте мне нужно иметь возможность ввести свой вызов defineProps
. Поскольку я хочу принять вычисленное значение, мне нужно, чтобы этот тип отображался здесь. Имеющееся у меня вычисляемое свойство очень велико, поэтому я не хочу вручную вводить его за пределами моего компонента и импортировать в оба. Вместо того, чтобы вводить его вручную, я просто использую оператор typeof
.
Как экспортировать этот тип?
// Parent.vue
<script setup lang = "ts">
const { results } = useQuery(...)
const myComputed = computed(() => results.nested.item.is.here)
</script>
<template>
<Child :passToMe = "myComputed" />
</template>
// Child.vue
const props = defineProps<
passToMe: ???
>()
Я видел, что вы можете экспортировать компонент с помощью отдельного тега <script>
, который будет работать, НО его область действия не позволяет видеть вычисленное свойство из моего <script setup>
.
Я мог бы просто использовать тип результатов gql, но, поскольку это значение вложенное, это не совсем работает.
Я не могу переместить запрос на дочерний уровень только для того, чтобы получить там тип, потому что мне нужны другие компоненты для использования компонента <Child>
, а этот тип в вычисленном <Parent>
является минимально необходимым типом, который я хочу обеспечить.
Итак, как мне экспортировать этот тип для использования в нескольких местах?
@EstusFlask абсолютно, но как мне экспортировать тип из родительского в дочерний. Тип представляет собой огромный объект со множеством полей, и я не хочу вводить его вручную. Мне потребовались бы часы, прежде чем я смог бы сделать что-то вроде:export typeof myComputed.value
и импортировать это в дочерний элемент.
Обычно вам нужно ввести его вручную. Это уже дополнительная работа и потенциальная точка отказа для defineProps для обработки импортированных типов, я считаю, что в какой-то момент это было недоступно. Легко ли этого избежать, зависит от особенностей useQuery. Что это, @vue/apollo-composable
? Вероятно, вы могли бы извлечь из него тип. Самый простой подход — переместить useMyQuery = () => useQuery(...) в отдельный модуль и использовать ReturnType<typeof useMyQuery>. Поскольку это то, что повторно используется между компонентами, оно в любом случае принадлежит отдельному модулю.
Обычно Vue SFC не экспортирует ничего, кроме самого компонента. Они могут выполнять именованный экспорт, но тот факт, что в некоторых IDE и других инструментах это не удается, доказывает, что это крайний случай.
Это кажется большим упущением, если вы не можете экспортировать типы, используемые в компоненте, когда вам приходится использовать указанный тип в дочернем/родительском компоненте. «поскольку он используется повторно, он в любом случае принадлежит отдельному модулю». Для меня это имеет смысл, но необходимость вводить его вручную, когда он уже существует где-то в коде, кажется упущением.
Проблема в вашем случае заключается в том, что useQuery() находится в области функции настройки, а экспорт должен быть на верхнем уровне, это не просто проблема с <настройкой сценария>. Возможно, вам не придется вводить его вручную с помощью ReturnType<typeof useMyQuery>. Но сделать это все еще может быть жизнеспособным вариантом. В зависимости от случая это можно считать оптимизацией, поскольку вывод типа в TS может требовать больших ресурсов.
вы можете получить тип «results.nested.item.is.here» с помощью typeof
const results = {
nested: {
item: {
is: {
here: "hello"
}
}
}
}
export type propsType = typeof results.nested.item.is // { here: string }
Затем импортируйте тип propsType
в свой компонент Child
.
typeof
немного особенный, потому что он не делает одно и то же во время выполнения javascript и в объявлениях типов машинописного текста.
Следующая строка даст вам тип javascript: либо "string"
, "object"
, "number"
... Это не то, что вам нужно.
export const runTimeType = typeof results.nested.item.is // "object"
В качестве альтернативы, если у вас есть доступ к типу результатов, вы можете сделать что-то вроде этого:
interface IResult {
nested : {
item : {
is : {
here: string
}
}
}
}
const results: IResult = {
nested: {
item: {
is: {
here: "hello"
}
}
}
}
export type propsType = IResult["nested"]["item"]["is"] // { here: string }
Как правило, я был бы осторожен с использованием typeof
, потому что, если typeof useQuery(...)
изменится, это также неявно изменит тип реквизита Child
, потенциально создавая ошибки, если новый тип несовместим с тем, как Child использует данные.
Спасибо, этого достаточно. Я не осознавал, что можно получить вложенный тип. Поскольку типы useQuery являются внешними по отношению к вычисляемому, а вычисляемый просто получает вложенный тип, мы можем сделать это в отдельном модуле и импортировать его в оба места. Спасибо
Вычисленное значение развернуто, тип passToMe — это любой тип «results.nested.item.is.here».