Type 'GraphQLResult | Observable<object>' is not assignable to type '{ data: CreateDocumentMutation; }'.
Type 'GraphQLResult' is not assignable to type '{ data: CreateDocumentMutation; }'.
Types of property 'data' are incompatible.
Type 'object | undefined' is not assignable to type 'CreateDocumentMutation'.
Type 'undefined' is not assignable to type 'CreateDocumentMutation'. TS2322
Getting the above error using typescript after the new Amplify js version.
It would be better to use Observable<any>
in this case because using type object
is incompatible. In TypeScript the type object
is the opposite of any
and is not assignable to anything.
@selipso, can you share your code sample where you are getting this error?
async deleteDocument(id: string): Promise<{data:DeleteDocumentMutation}> {
return API.graphql(graphqlOperation(deleteDocument, { input: { id } }));
}
Fairly simple wrapper function around the graphQL operation. The mutation deleteDocument
and type DeleteDocumentMutation
are auto-generated from the CLI using TypeScript. The data returned from the backend matches the type declarations but TypeScript complains.
Agreed, I don't see how Observable
applies here. API.graphql()
should return a GraphQLResult
only. And if I typecast it to GraphQLResult
, I still have issues:
Also, this:
export interface GraphQLResult {
data?: object;
errors?: [object];
extensions?: {
[key: string]: any;
};
}
I would probably change the data
line to:
data?: Record<string, any>;
@ffxsam It's complaining about result.data.createFolder
because result.data
is optional. Once TypeScript 3.7 is release this will be much easier
return result.data?.createFolder;
There's a PR to add support for generics to the API's which helps with some of the stuff mentioned here. See #3748
There's been much discussion about the return type of API.graphql()
. Basically it's a GraphQLResult
if you're performing a query
/mutation
and an Observable
if you're performing a subscription
@buggy That's actually not true, as you can see above I'm checking for falsey values for result
and result.data
(which is partially blocked by the popup message).
It still gives me that error. And yeah, I haven't started using subscriptions yet, so your comment about Observable
makes sense to me now.
@ffxsam I couldn't see the code behind the popup :(
The PR that I mentioned above should solve your problem once it's merged. It uses generics allowing your define the structure of the variables passed and data returned.
Something like:
API.graphql<{createFolder: SOMETYPE}>(...)
Would allow you to access
result.data?.createFolder
Thanks for the feedback and updates. Because of the convenient wrapper provided by API.graphql I am very happy with type ‘any’ and referring to the documentation for the data structure.
The generics solution is also fine or even Promise<{data:any}> & Observable<{data:any}>
I ended up having a deep dive into intersection types and union types because of this issue and believe the above format is appropriate considering Angular users who are also used to observables.
I'm seeing a similar issue with await API.graphql()
. When trying to access data
from the returned result:
TS2339: Property 'data' does not exist on type 'GraphQLResult | Observable<object>'.
Property 'data' does not exist on type 'Observable<object>'.
we've solved this by adding an 'as unknown'.
If you have a better way to type, do not hesitate to share.
(API.graphql(graphqlOperation(createAttributeMutation, { input: payload })) as unknown) as {
data: CreateAttributeMutation
}
I would use TS function overloading to achieve smarter return values so we don't have to bother with typecasting:
See example here, and mouse over result1
and result2
to see that the types are different.
I realize this is a breaking change due to the parameters, but IMO this is better DX (developer experience). @selipso @mlabieniec
any updates? seems like I always get a Promise and not Observable. It is a little annoying
Here's how I did it!
...
graphql<T>({ query: paramQuery, variables, authMode }: GraphQLOptions): Promise<GraphQLResult<T>> | Observable<T> & { [key: string]: any };
...
...
export interface GraphQLResult<T> {
data?: T;
errors?: [object];
extensions?: {
[key: string]: any;
};
}
...
graphql<T>
for more flexible response data type.Observable<T>
with { [key: string]: any }
declaration to the .graphql<T>(...)
return type instead of adding { data?: any }
which Observable will never have.This problem popped up for me during the React Amplify tutorial https://docs.amplify.aws/start/getting-started/data-model/q/integration/react#connect-frontend-to-api
Line 23-24:
const todoData = await API.graphql(graphqlOperation(listTodos))
const todos = todoData.data.listTodos.items
The error is:
Property 'data' does not exist on type 'GraphQLResult<object> | Observable<object>'.
Property 'data' does not exist on type 'Observable<object>'.ts(2339)
I managed to go around this problem by using this obvious kludge:
const todoData: any = await API.graphql(graphqlOperation(listTodos))
It would be nice with a proper solution though ;)
^ This is the workaround I've been using too
@michalmikolajczyk @selipso as you know using any
disables type checking.
Until #5208 or #3748 get through, try something like this:
import { GraphQLResult } from "@aws-amplify/api";
import { ListTodosQuery } from "./api";
// ...
const todoData = (
await API.graphql(graphqlOperation(listTodos))
) as GraphQLResult<ListTodosQuery>;
const todos = todoData.data.listTodos.items
@michalmikolajczyk @selipso as you know using
any
disables type checking.Until #5208 or #3748 get through, try something like this:
import { GraphQLResult } from "@aws-amplify/api"; import { ListTodosQuery } from "./api"; // ... const todoData = ( await API.graphql(graphqlOperation(listTodos)) ) as GraphQLResult<ListTodosQuery>; const todos = todoData.data.listTodos.items
This results in todoData possibly 'undefined'
@michalmikolajczyk @selipso as you know using
any
disables type checking.
Until #5208 or #3748 get through, try something like this:import { GraphQLResult } from "@aws-amplify/api"; import { ListTodosQuery } from "./api"; // ... const todoData = ( await API.graphql(graphqlOperation(listTodos)) ) as GraphQLResult<ListTodosQuery>; const todos = todoData.data.listTodos.items
This results in todoData possibly 'undefined'
Probably because you're using strict: true
in your tsconfig.json
. Try something like:
const todos = todoData?.data?.listTodos?.items
But be aware that items
may be null
, or even null[]
, (check the generated type definition). You have to handle this, in any way makes sense for your project, to keep type consistency.
I'm also trying to follow along with https://docs.amplify.aws/start/getting-started/data-model/q/integration/react-native#connect-frontend-to-api with Typescript by trying to add a new screen inside of https://github.com/ethanneff/react-native-web-typescript.
My issue is with the type to useState
src/screens/Amplify/index.tsx:33:18 - error TS2345: Argument of type '({ __typename: "Todo"; id: string; name: string; description: string | null; createdAt: string; updatedAt: string; } | null)[]' is not assignable to parameter of type 'SetStateAction<never[]>'.
Type '({ __typename: "Todo"; id: string; name: string; description: string | null; createdAt: string; updatedAt: string; } | null)[]' is not assignable to type 'never[]'.
Type '{ __typename: "Todo"; id: string; name: string; description: string | null; createdAt: string; updatedAt: string; } | null' is not assignable to type 'never'.
Type 'null' is not assignable to type 'never'.
33 setTodos(todos);
I've solved it by for now by passing <any[]>
and putting a guard around setTodos
but that doesn't feel quite right here...
const [todos, setTodos] = useState<any[]>([]); //TODO: Fix the type here
...
if (todos) {
setTodos(todos);
}
Any experts with a better fix?
It's because need using Observable not from rxjs, but zen-observable-ts
im getting this do any one have solution for this
"Property 'data' does not exist on type 'GraphQLResult
@mauerbac I fail to see how this is a feature request. The codegen feature shouldn't produce code that needs to be manually modified/overridden for it to work..
Changing the imports in the generated api.service.ts from zen-observable
to zen-observable-ts
does fix the errors for me, though.
i add any: and it fixed my problem
Le ven. 27 nov. 2020 Ã 21:39, Sean van Mulligen notifications@github.com
a écrit :
@mauerbac https://github.com/mauerbac I fail to see how this is a
feature request. The codegen feature shouldn't produce code that needs to
be manually modified/overridden for it to work..Changing the imports in the generated api.service.ts from zen-observable
to zen-observable-ts does fix the errors for me, though.—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/aws-amplify/amplify-js/issues/4257#issuecomment-734984641,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/ARSWRDSHE4ERADFSJVSTIRDSSAE67ANCNFSM4JE6JE2Q
.
but i still have this problem do you know how to solve it
Le ven. 27 nov. 2020 Ã 21:39, Sean van Mulligen notifications@github.com
a écrit :
@mauerbac https://github.com/mauerbac I fail to see how this is a
feature request. The codegen feature shouldn't produce code that needs to
be manually modified/overridden for it to work..Changing the imports in the generated api.service.ts from zen-observable
to zen-observable-ts does fix the errors for me, though.—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/aws-amplify/amplify-js/issues/4257#issuecomment-734984641,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/ARSWRDSHE4ERADFSJVSTIRDSSAE67ANCNFSM4JE6JE2Q
.
any updates on it?
I don't like to have any
type in code
I ran into something like this with @connection .. it doesn't write out the connected data types only a subset.
type Asset @model
@key(name: "assetTitleIndex", fields: ["title"], queryField: "assetsByTitle")
@key(name: "assetFolderIndex", fields: ["folder", "owner"], queryField: "assetsByFolder")
@key(name: "assetOwnerIndex", fields: ["owner", "folder"], queryField: "assetsByOwner")
{
id: ID!
owner: ID!
attempts: [Attempt] @connection(keyName: "attemptByAssetIndex", fields: ["id", "owner"])
folder: String!
title: String!
description: String
size: Int!
manifest: AWSJSON!
version: String!
public: Boolean
editors: [ID]
createdAt: AWSDateTime
updatedAt: AWSDateTime
}
type Attempt @model
@key(name: "attemptByOwnerIndex", fields: ["owner"], queryField: "attemptByOwner")
@key(name: "attemptByAssetIndex", fields: ["asset", "owner"], queryField: "attemptByAsset")
{
id: ID!
owner: ID!
asset: ID!
satisfied: Boolean!
progress: Boolean!
completion: Boolean
score: Int!
data: AWSJSON!
attempts: Int!
exitType: String!
createdAt: AWSDateTime
updatedAt: AWSDateTime
}
Results in a API.service.ts:
OnCreateAssetListener: Observable<
SubscriptionResponse<OnCreateAssetSubscription>
> = API.graphql(
graphqlOperation(
`subscription OnCreateAsset {
onCreateAsset {
__typename
id
owner
attempts {
__typename
// THIS PART IS MISSING
items {
__typename
id
owner
asset
satisfied
progress
completion
score
data
attempts
exitType
createdAt
updatedAt
}
// PART MISSING
nextToken
}
folder
title
description
size
manifest
version
public
editors
createdAt
updatedAt
}
}`
)
) as Observable<SubscriptionResponse<OnCreateAssetSubscription>>;
And any section that needs it. I manually put it back in but if I touch the schema it wipes it out again.
Most helpful comment
This problem popped up for me during the React Amplify tutorial https://docs.amplify.aws/start/getting-started/data-model/q/integration/react#connect-frontend-to-api
Line 23-24:
The error is:
I managed to go around this problem by using this obvious kludge:
It would be nice with a proper solution though ;)