amplify-codegen
amplify-codegen copied to clipboard
Generated Typescript types are inconsistent
Before opening, please confirm:
- [X] I have installed the latest version of the Amplify CLI (see above), and confirmed that the issue still persists.
- [X] I have searched for duplicate or closed issues.
- [X] I have read the guide for submitting bug reports.
- [X] I have done my best to include a minimal, self-contained set of instructions for consistently reproducing the issue.
- [X] I have removed any sensitive information from my code snippets and submission.
How did you install the Amplify CLI?
yarn
If applicable, what version of Node.js are you using?
16.13.0
Amplify CLI Version
7.6.20
What operating system are you using?
mac
Did you make any manual changes to the cloud resources managed by Amplify? Please describe the changes made.
No
Amplify Categories
api
Amplify Commands
codegen
Describe the bug
Using GraphQL and Opensearch, Amplify defines the following types in src/API.ts:
export type SearchableInvoiceConnection = {
__typename: "SearchableInvoiceConnection",
items: Array<Invoice | null >,
nextToken?: string | null,
total?: number | null,
aggregateItems: Array<SearchableAggregateResult | null >,
};
export type SearchableAggregateResult = {
__typename: "SearchableAggregateResult",
name: string,
result?: SearchableAggregateGenericResult | null,
};
export type SearchableAggregateGenericResult = SearchableAggregateScalarResult | SearchableAggregateBucketResult
export type SearchableAggregateScalarResult = {
__typename: "SearchableAggregateScalarResult",
value: number,
};
export type SearchableAggregateBucketResult = {
__typename: "SearchableAggregateBucketResult",
buckets?: Array<SearchableAggregateBucketResultItem | null > | null,
};
export type SearchableAggregateBucketResultItem = {
__typename: "SearchableAggregateBucketResultItem",
key: string,
doc_count: number,
};
Based on these, I should be able to write a type guard that I can use when iterating over the aggregates returned by OpenSearch to distinguish bucket results from scalar results:
export function isSearchableAggregateBucketResult(
item: SearchableAggregateGenericResult | null | undefined
): item is SearchableAggregateBucketResult {
return item !== null && item !== undefined && "buckets" in item;
}
However, this code produces an error:
TS2345: Argument of type '{ __typename: "SearchableAggregateScalarResult"; value: number; } | { __typename: "SearchableAggregateBucketResult"; buckets?: ({ __typename: string; key: string; doc_count: number; } | null)[] | null | undefined; } | null' is not assignable to parameter of type 'SearchableAggregateGenericResult | null | undefined'.
The reason for this is that the type of the OpenSearch results doesn't use any of the above types. Instead, it's typed this way:
export type SearchInvoicesQuery = {
searchInvoices?: {
__typename: "SearchableInvoiceConnection",
items: Array< {
__typename: "Invoice",
id: string,
supplier_paidol_id: string,
supplier_paidol_name: string,
accounts_receivable_name: string,
date_sent: string,
date_due: string,
createdAt: string,
sentAt?: string | null,
status: InvoiceStatus,
updatedAt: string,
} | null >,
nextToken?: string | null,
total?: number | null,
aggregateItems: Array< {
__typename: "SearchableAggregateResult",
name: string,
result: ( {
__typename: "SearchableAggregateScalarResult",
value: number,
} | {
__typename: "SearchableAggregateBucketResult",
buckets?: Array< {
__typename: string,
key: string,
doc_count: number,
} | null > | null,
}
) | null,
} | null >,
} | null,
};
Although the typing references __typename: "SearchableInvoiceConnection"
, etc., the types are not actually composed here. This means that the type guard needs to be written like this:
export function isSearchableAggregateBucketResult(
item:
| { __typename: "SearchableAggregateScalarResult"; value: number }
| {
__typename: "SearchableAggregateBucketResult";
buckets?:
| ({ __typename: string; key: string; doc_count: number } | null)[]
| null
| undefined;
}
| null
| undefined
): item is SearchableAggregateBucketResult {
return item !== null && item !== undefined && "buckets" in item;
}
Expected behavior
API.ts should either use the types it defines, or those types should not be exposed to developers. They are not usable in their current form.
Reproduction steps
Define any @model @searchable
in GraphQL and consume the results in Typescript.
GraphQL schema(s)
type Invoice
@model(mutations: null, subscriptions: null)
@auth(rules: [{ allow: public, provider: iam, operations: [read] }])
@searchable {
id: ID!
supplier_paidol_id: ID!
supplier_paidol: Paidol @hasOne(fields: ["supplier_paidol_id"])
supplier_paidol_name: String!
accounts_receivable_name: String!
date_sent: AWSDateTime!
date_due: AWSDateTime!
balance_due: Currency
createdAt: AWSDateTime!
sentAt: AWSDateTime
status: InvoiceStatus!
items: [InvoiceItem] @hasMany(indexName: "byInvoice", fields: ["id"])
}
Log output
ERROR in src/store/invoicesSlice.ts:79:49
TS2345: Argument of type '{ __typename: "SearchableAggregateScalarResult"; value: number; } | { __typename: "SearchableAggregateBucketResult"; buckets?: ({ __typename: string; key: string; doc_count: number; } | null)[] | null | undefined; } | null' is not assignable to parameter of type 'SearchableAggregateGenericResult | null | undefined'.
Type '{ __typename: "SearchableAggregateBucketResult"; buckets?: ({ __typename: string; key: string; doc_count: number; } | null)[] | null | undefined; }' is not assignable to type 'SearchableAggregateGenericResult | null | undefined'.
Type '{ __typename: "SearchableAggregateBucketResult"; buckets?: ({ __typename: string; key: string; doc_count: number; } | null)[] | null | undefined; }' is not assignable to type 'SearchableAggregateBucketResult'.
Types of property 'buckets' are incompatible.
Type '({ __typename: string; key: string; doc_count: number; } | null)[] | null | undefined' is not assignable to type '(SearchableAggregateBucketResultItem | null)[] | null | undefined'.
Type '({ __typename: string; key: string; doc_count: number; } | null)[]' is not assignable to type '(SearchableAggregateBucketResultItem | null)[]'.
Type '{ __typename: string; key: string; doc_count: number; } | null' is not assignable to type 'SearchableAggregateBucketResultItem | null'.
Type '{ __typename: string; key: string; doc_count: number; }' is not assignable to type 'SearchableAggregateBucketResultItem'.
Types of property '__typename' are incompatible.
Type 'string' is not assignable to type '"SearchableAggregateBucketResultItem"'.
77 | .filter(isNotNull)
78 | .reduce<AggregatesMap>((accumulator, current) => {
> 79 | if (isSearchableAggregateBucketResult(current.result)) {
| ^^^^^^^^^^^^^^
80 | accumulator[current.name] = (current.result.buckets ?? [])
81 | .filter(isNotNull)
82 | .map((item) => item.key)
Additional information
No response