reactjs - როგორ გამოავლინოთ Apollo Query-ის ტიპი Typescript-ით


მეც ვცდილობ, რომ Apollo გააერთიანოს TypeScript-თან. მაქვს React კლასი, რომელიც ასე გამოიყურება:

interface Data {
  allVendors: Array<VendorType>;
}

class AllVendorsQuery extends Query<Data> {}

const ShowVendors: React.SFC<> = props => {
  return (
    <AllVendorsQuery query={fetchVendors}>
      {({ loading, error, data: { allVendors } }) => {
        if (loading) {
          return 'Loading...';
        }
        if (error) {
          return `Error! ${error.message}`;
        }

        return (
          allVendors &&
          allVendors.map((vendor, index: number) => {
            return (
              <div key={`${vendor.name}_${index}`}>
                #<strong>{vendor.id}</strong>
                &nbsp;{vendor.name}
              </div>
            );
          })
        );
      }}
    </AllVendorsQuery>
  );
};

export default ShowVendors;

კითხვა არის:

export default gql`
  query GetVendors {
    allVendors {
      id
      name
    }
  }
`;

TypeScript იუწყება იმ ფაქტზე, რომ [ts] ტიპს 'Data | undefined' არ აქვს საკუთრება 'allVendors' და არ აქვს სტრინგის ინდექსის სიგნატურა. რაც ხდება ამ ხაზზე: {({ loading, error, data: { allVendors } }).

თუმცა, თუ მე კოდს გადავაწყობ apollo-connect-ის გამოყენებით Query კომპონენტის ნაცვლად, TypeScript-იდან არცერთი განცხადება არ მივიღებ:

import { graphql, compose, QueryResult } from 'react-apollo';

interface ShowVendorsProps {
  data: QueryResult & { allVendors?: VendorType[] };
}

class ShowVendors extends React.Component<ShowVendorsProps> {
  render() {
    const {
      data: { allVendors }
    } = this.props;

    if (allVendors && allVendors.length > 0) {
      return (
        <div>
          {allVendors.map((vendor, index: number) => {
            return (
              <div key={`${vendor.name}_${index}`}>
                #<strong>{vendor.id}</strong>
                &nbsp;{vendor.name}
              </div>
            );
          })}
        </div>
      );
    } else {
      return 'Loading';
    }
  }
}

export default compose(graphql(fetchVendors))(ShowVendors);

რა განსხვავებაა ამ ორ შორის? როგორ შემიძლია გადამინიშნოს ტიპი პირველი განაცხადისთვის?

პასუხი #1

არსებობს პატარა ბიბლიოთეკა და CLI TypeScript-ის ტიპების შექმნისთვის როგორც სერვერისთვის (თქვენი სქემის მიხედვით), ასევე კლიენტისთვის (თქვენი სქემისა და GraphQL დოკუმენტების მიხედვით). ის ასევე ქმნის რეზოლვერების სიგნატურას და ძალიან პერსონალიზებადი არის.

თქვენ შეგიძლიათ სცადოთ ეს აქ: https://github.com/dotansimha/graphql-code-generator

აქ არის ბლოგის პოსტი იმ პაკეტზე; https://medium.com/the-guild/graphql-code-generator-for-typescript-react-apollo-7b225672588f

მისი ძირითადი იდეა იყო, რომ დეველოპერს უნდა მიეცეს შესაძლებლობა მაქსიმალურად გამოიყენოს GraphQL და გენერირებული ტიპები, ხოლო გენერირებული შედეგი მარტივად მორგებად უნდა იყოს.

ის ასევე შეუძლია შექმნას react-apollo კომპონენტები საჭირო ტიპიზაციებით.

პასუხი #2

რადგან თქვენ ანგრევთ data-ს data: { allVendors } პირველ კოდბლოკში, TypeScript-ს უჩივის, რადგან data შესაძლოა აურზაურელი იყოს, მაგალითად, როცა მონაცემები ჯერ კიდევ ითვლება.

უჯოკ TS-ში ჩივილის გარეშე, თქვენ უბრალოდ შეგიძლიათ დაშალოთ მონაცემები ჩატვირთვის შემოწმების შემდეგ, allVendors-ისთვის ნაგულისხმევი მნიშვნელობებით, რაღაც როგორიცაა:

interface Data {
  allVendors: Array<VendorType>;
}

class AllVendorsQuery extends Query<Data> {}

const ShowVendors: React.SFC<> = props => {
  return (
    <AllVendorsQuery query={fetchVendors}>
      {({ loading, error, data }) => {
        if (loading) {
          return 'Loading...';
        }
        if (error) {
          return `Error! ${error.message}`;
        }

        // If data is not undefined, then it sets allVendors accordingly.
        // Otherwise it sets it to null (which you check for anyways below)             
        const {allVendors} = data || {allVendors: null}; 

        return (
          allVendors &&
          allVendors.map((vendor, index: number) => {
            return (
              <div key={`${vendor.name}_${index}`}>
                #<strong>{vendor.id}</strong>
                &nbsp;{vendor.name}
              </div>
            );
          })
        );
      }}
    </AllVendorsQuery>
  );
};

export default ShowVendors;