简体   繁体   English

typescript 无法解析来自返回联合类型的 graphql 查询的类型

[英]typescript can't resolve typing from graphql query that returns a union type

I would like to understand what is going on here, and since i'm not very experienced with typescript, any help would be greatly appreciated !我想了解这里发生了什么,并且由于我对 typescript 不是很有经验,因此将不胜感激任何帮助!

I've got a resolver to return one cost from database:我有一个解析器从数据库返回一个成本:

  @Query(() => FixedOrVariableCost, { name: 'oneCost' })
  async getOneCost(
    @Args('id', { type: () => String }) id: MongooseSchema.Types.ObjectId
  ) {
    return this.costsService.getOneCost(id);
  }

Its return type FixedOrVariableCost is a union type:它的返回类型 FixedOrVariableCost 是一个联合类型:

const FixedOrVariableCost = createUnionType({
  name: 'FixedOrVariableCost',
  types: () => [FixedCost, VariableCost] as const,
});

Basically in my model, a cost is a fixed or a variable one.基本上在我的 model 中,成本是固定的或可变的。 Cost is an abstract interface in my graphql layer. Cost 是我的 graphql 层中的一个抽象接口。

Generated schema:生成的架构:

union FixedOrVariableCost = FixedCost | VariableCost

oneCost(id: String!): FixedOrVariableCost!

Here is the query i'm using:这是我正在使用的查询:

const useGetOneCost = (id: string) =>
  useQuery(['getOneCost', id], async () => {
    return (
      graphQLClient.request(
        gql`
          query GetOneCost($id: String!) {
            oneCost(id: $id) {
              ... on Cost {
                _id
                kind
                code
                label
                title
                content
                costType {
                  _id
                  code
                  label
                }
                costMargin {
                  _id
                  code
                  label
                }
                createdAt
                createdBy {
                  _id
                }
                updatedAt
                updatedBy {
                  _id
                }
                status {
                  _id
                  code
                  label
                  color
                }
              }
              ... on FixedCost {
                fixedCostValue {
                  amount
                  currency {
                    _id
                    code
                    label
                    symbol
                  }
                }
              }
              ... on VariableCost {
                variableCostValue
              }
            }
          }
        `,
        { id }
      ),
      {
        enabled: !!id,
      }
    );
  });

The typing generated by graphql codegen is the following: graphql codegen 生成的类型如下:

export type GetOneCostQuery = {
  __typename?: 'Query';
  oneCost:
    | {
        __typename?: 'FixedCost';
        _id: string;
        kind: CostKind;
        code: string;
        label: string;
        title?: string | null;
        content?: string | null;
        createdAt: any;
        updatedAt: any;
        costType: {
          __typename?: 'CostType';
          _id: string;
          code: string;
          label: string;
        };
        costMargin: {
          __typename?: 'CostMargin';
          _id: string;
          code: string;
          label: string;
        };
        createdBy: { __typename?: 'User'; _id: string };
        updatedBy: { __typename?: 'User'; _id: string };
        status: {
          __typename?: 'GenericStatus';
          _id: string;
          code: string;
          label: string;
          color: string;
        };
        fixedCostValue: {
          __typename?: 'FixedCostValue';
          amount: number;
          currency: {
            __typename?: 'Currency';
            _id: string;
            code: string;
            label: string;
            symbol: string;
          };
        };
      }
    | {
        __typename?: 'VariableCost';
        _id: string;
        kind: CostKind;
        code: string;
        label: string;
        title?: string | null;
        content?: string | null;
        createdAt: any;
        updatedAt: any;
        variableCostValue: number;
        costType: {
          __typename?: 'CostType';
          _id: string;
          code: string;
          label: string;
        };
        costMargin: {
          __typename?: 'CostMargin';
          _id: string;
          code: string;
          label: string;
        };
        createdBy: { __typename?: 'User'; _id: string };
        updatedBy: { __typename?: 'User'; _id: string };
        status: {
          __typename?: 'GenericStatus';
          _id: string;
          code: string;
          label: string;
          color: string;
        };
      };
};

very nice !非常好 ! Typing generation works as expected打字生成按预期工作

Now, one of my component receives a cost as a prop, so i'm picking oneCost inside GetOneCostQuery type现在,我的一个组件接收成本作为道具,所以我在GetOneCostQuery类型中选择oneCost

type PropType<TObj, TProp extends keyof TObj> = TObj[TProp];

type OneCost = PropType<GetOneCostQuery, 'oneCost'>;

type Props = {
  cost: OneCost;
};

export const MyComponent = ({
  cost
}: Props) => {
  console.log(cost.fixedCostValue);
  return null;
}

ts error on ``fixedCostValue: ``fixedCostValue 上的 ts 错误:

La propriété 'fixedCostValue' n'existe pas sur le type '{ __typename?: "FixedCost" | undefined; _id: string; kind: CostKind; code: string; label: string; title?: string | null | undefined; content?: string | null | undefined; createdAt: any; ... 6 more ...; fixedCostValue: { ...; }; } | { ...; }'.
  La propriété 'fixedCostValue' n'existe pas sur le type '{ __typename?: "VariableCost" | undefined; _id: string; kind: CostKind; code: string; label: string; title?: string | null | undefined; content?: string | null | undefined; createdAt: any; ... 6 more ...; status: { ...; }; }'.ts(2339)

roughly in english: "Property 'fixedCostValue' doesn't exist on type blablabla"大致用英语:“blablabla 类型不存在属性‘fixedCostValue’”

Shouldn't this value maybe available, if cost is a fixed one?如果成本是固定的,这个值不应该是可用的吗? Why can't typescript recognize this value?为什么 typescript 不能识别这个值? This confuses me...这让我很困惑...

Thanks for your help谢谢你的帮助

Type OneCost is a union, meaning it is one of two objects - either FixedCost or VariableCost .类型OneCost是一个联合,这意味着它是两个对象之一 - FixedCostVariableCost While the first contains an attribute named fixedCostValue , the second one doesn't, hence the error.虽然第一个包含一个名为fixedCostValue的属性,但第二个没有,因此出现错误。

If you'll check if this attribute exists in the object, it'll pass.如果您检查 object 中是否存在此属性,它将通过。 for example:例如:

export const MyComponent = ({
  cost
}: Props) => {
  if ("fixedCostValue" in cost) {
    console.log(cost.fixedCostValue);
  };
  return null;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM