vue-apollo - Property 'value' does not exist on type 'Readonly<Ref<Readonly<any>>>'

Viewed 520

THE SITUATION:

I am trying to integrate vue-apollo v4 with Typescript.

I am fetching a simple query using useQuery and useResult.

useResult by default return this type: Readonly<Ref<Readonly<any>>>

THE CODE:

import { GET_COUNTRY } from '../graphql/queries'
import { Country } from '../types'

setup() {
  const route = useRoute()
  const code = route.params.code

  const { result, loading } = useQuery(GET_COUNTRY, {code: code}, { 
    clientId: 'default', 
    fetchPolicy: 'cache-first'
  });
  const country = useResult(result, {}, (data) => data.country);

  console.log(country.name) // Property 'name' does not exist on type 'Readonly<Ref<Readonly<any>>>'.ts(2339)

  return {
    country,
    loading
  }
}

ATTEMPT 1:

const country: Country = useResult(result, {}, (data) => data.country);
// Type 'Readonly<Ref<Readonly<any>>>' is missing the following properties from type 'Country': native, phone, capital, currency, and 6 more.ts(2740)

ATTEMPT 2:

const country = useResult(result, {}, (data) => data.country as Country);
console.log(country.name) // Property 'name' does not exist on type 'Readonly<Ref<Readonly<any>>>'.ts(2339)

ATTEMPT 3:

const country: Country = useResult(result, {}, (data) => data.country as Country);
// Type 'Readonly<Ref<Readonly<Country | {}>>>' is missing the following properties from type 'Country': native, phone, capital, currency, and 6 more.ts(2740)

ATTEMPT 4:
After feedback from @tony19

const { result, loading } = useQuery<Country>(GET_COUNTRY, {code: code});
const country = useResult(result, {}, (data) => data.country);
// Property 'country' does not exist on type '{ native: string; phone: string; capital: string; currency: string...

ATTEMPT 5:
After edited answer from @tony19

// QUERY - simplified
export const GET_COUNTRY = gql`
  query getCountry($code: ID!) {
    country(code: $code) {
      code
      name
    }
  }
`
// TYPES - simplified
export interface Country {
  code: string,
  name: string
}

export type CountryQuery = {
  country: Country
}
const { result, loading } = useQuery<CountryQuery>(GET_COUNTRY, {code: code});
const country = useResult(result, {}, (data) => data.country);

I am getting the following warning in vsCode:

 Property 'name' does not exist on type 'Readonly<{}>'.

Property 'name' does not exist on type 'Readonly<{}>'

ATTEMPT 5b:
If, as in @tony19 answer, I do the following type:

type CountryQuery = {
  getCountry: Country
}

Then I am getting this error:

Property 'country' does not exist on type '{ getCountry: { code: string; name: string; }; }'

Property 'country' does not exist on type '{ getCountry: { code: string; name: string; }; }'

THE QUESTION:

Is it possible to combine useResult with my own Typescript interface?

1 Answers

Assuming the following types:

type Country = {
  name: string
}

const GET_COUNTRY = gql`
  query GetCountry {
    getCountry {
      name
    }
  }
`

The result should be typed to match the GET_COUNTRY query above:

type CountryQuery = {
  getCountry: Country
}

Then, specify that query type as a type argument to useQuery():

const { result, loading } = useQuery<CountryQuery>(GET_COUNTRY, ⋯)
                                        

Now, the data argument of useResult()'s callback is of type CountryQuery, so use data.getCountry.name to get the country name:

                                         type is CountryQuery
const country = useResult(result, {}, (data) => data.getCountry.name);
                                                        

result and country are refs, so to access the underlying data, unwrap them with .value:

console.log(country.value);
                      

demo

Related