admin管理员组文章数量:1410682
I created a Fetch function to consume a JSON API and have defined types for the JSON object. I am confused about how to define the return type for the getCurrentJobAPI
function since I do a bunch of .then()
afterwards. Is the return value the last .then()? In my code, the last .then() is a setState, so what would the type be for that?
getCurrentJobAPI = (): {} => {
const url: string = `dummy_url&job_id=${this.props.currentJob}`;
return fetch(url, {credentials: 'include'})
.then((response) => {
return response.json();
})
.then((json: CurrentJob) => {
console.log(json);
const location = json.inventoryJob.location;
const ref_note = json.inventoryJob.note;
const id = json.inventoryJob.id;
const models = json.inventoryJobDetails.map((j) => {
return Object.assign({}, {
code: j.code,
qty: j.qty
})
});
this.setState({ currentCodes: models, location: location, ref_note: ref_note, id: id})
return json
})
.then((json: CurrentJob) => {
const barcodes = json.inventoryJob.history;
if (barcodes.length > 0) {
this.setState({apiBarcodes: barcodes})
}
this.calculateRows();
this.insertApiBarcodes();
this.setState({ initialLoad: true });
})
};
UPDATE:
Although I understand that I am supposed to define Promise<type>
as the return value of getCurrentJobAPI
(see Gilad's answer and ments), I am still unsure why I can't write Promise<CurrentJob>
if the Fetch resolves as the JSON response.
[I have condensed my .then() statements per loganfsmyth's remondation.]
Here are the type definitions for CurrentJob
:
type Job = {
user_id: number,
status: 'open' | 'closed',
location: 'string',
history: {[number]: string}[],
note: string,
} & CommonCurrentJob;
type JobDetails = {
iaj_id: number,
code: number,
} & CommonCurrentJob;
type CommonCurrentJob = {
id: number,
qty: number,
qty_changed: number,
created_at: string,
updated_at: string
}
I created a Fetch function to consume a JSON API and have defined types for the JSON object. I am confused about how to define the return type for the getCurrentJobAPI
function since I do a bunch of .then()
afterwards. Is the return value the last .then()? In my code, the last .then() is a setState, so what would the type be for that?
getCurrentJobAPI = (): {} => {
const url: string = `dummy_url&job_id=${this.props.currentJob}`;
return fetch(url, {credentials: 'include'})
.then((response) => {
return response.json();
})
.then((json: CurrentJob) => {
console.log(json);
const location = json.inventoryJob.location;
const ref_note = json.inventoryJob.note;
const id = json.inventoryJob.id;
const models = json.inventoryJobDetails.map((j) => {
return Object.assign({}, {
code: j.code,
qty: j.qty
})
});
this.setState({ currentCodes: models, location: location, ref_note: ref_note, id: id})
return json
})
.then((json: CurrentJob) => {
const barcodes = json.inventoryJob.history;
if (barcodes.length > 0) {
this.setState({apiBarcodes: barcodes})
}
this.calculateRows();
this.insertApiBarcodes();
this.setState({ initialLoad: true });
})
};
UPDATE:
Although I understand that I am supposed to define Promise<type>
as the return value of getCurrentJobAPI
(see Gilad's answer and ments), I am still unsure why I can't write Promise<CurrentJob>
if the Fetch resolves as the JSON response.
[I have condensed my .then() statements per loganfsmyth's remondation.]
Here are the type definitions for CurrentJob
:
type Job = {
user_id: number,
status: 'open' | 'closed',
location: 'string',
history: {[number]: string}[],
note: string,
} & CommonCurrentJob;
type JobDetails = {
iaj_id: number,
code: number,
} & CommonCurrentJob;
type CommonCurrentJob = {
id: number,
qty: number,
qty_changed: number,
created_at: string,
updated_at: string
}
Share
edited Nov 20, 2017 at 22:42
Avi Kaminetzky
asked Nov 20, 2017 at 19:17
Avi KaminetzkyAvi Kaminetzky
1,5382 gold badges21 silver badges45 bronze badges
5
-
1
The return value is the entire promise chain. You could technically take the result of
getCurrentJobAPI()
and attach morethen
andcatch
type things to it. Is that what you were asking? Otherwise I'm not sure what to say. You can't return anything other than the promise itself, because otherwise it would no longer be asynchronous. – Matt Fletcher Commented Nov 20, 2017 at 19:22 - If the return value is the entire promise chain, how can I define the type of Promise in Flow? Where is the documentation for such a case? – Avi Kaminetzky Commented Nov 20, 2017 at 19:28
- 1 You can't. That's not how async would work. If you tried running code after the promise chain, it would possibly run before the promise gets to the end. So you can't think of it as returning a value, because that is synchronous – Matt Fletcher Commented Nov 20, 2017 at 19:30
- Sorry, just realised that I haven't understood your question. My bad – Matt Fletcher Commented Nov 20, 2017 at 19:34
-
1
Not an answer to your question, but almost none of those
.then
s are needed. You use.then
either to return another promise, or as the final handler in a promise chain. Most of your intermediate.then
handlers just end up returningundefined
so you could collapse them into the first.then
. – loganfsmyth Commented Nov 20, 2017 at 20:00
2 Answers
Reset to default 5So first off, a disclaimer, I am a TypeScript user but I find that this question is actually applicable to both languages and has the same answer.
I created a Fetch function to consume a JSON API and have defined types for the JSON object. I am confused about how to define the return type for the getCurrentJobAPI function since I do a bunch of .then() afterwards. Is the return value the last .then()? In my code, the last .then() is a setState, so what would the type be for that?
TL;DR: Promise<void>
(see note). As you suspect, this is in fact the return type of the last top-level .then
in the promise chain.
Now lets dig a bit deeper
Here is your example, reworked very slightly to leverage type inference instead of annotating callback parameters that are declared as any
by their receivers.
As an aside, these callback parameter annotations amount to unsafe implicit casts, or type assertions as we call them in TypeScript, and they lie about the shape of the code. They look like this
declare function takesFn(fn: (args: any) => any): void;
So I have minimized these since they form a subtle trap
// @flow
import React from 'react';
type CurrentJob = {
inventoryJob: Job,
inventoryJobDetails: JobDetails[]
}
export default class A extends React.Component<{currentJob:JobDetails}, any> {
getCurrentJobAPI: () => Promise<void> = () => {
const url = `dummy_url&job_id=${String(this.props.currentJob)}`;
return fetch(url, {credentials: 'include'})
.then(response => {
return (response : {json(): any}).json();
}) // --> Promise<any>
.then(json => {
const currentJob = (json: CurrentJob); // make the assumption explicit.
console.log(currentJob);
const {location, id, note: ref_note} = currentJob.inventoryJob;
const currentCodes = currentJob.inventoryJobDetails
.map(({code, qty}) => ({
code,
qty
}));
this.setState({currentCodes, location, ref_note, id});
return currentJob;
}) // --> Promise<CurrentJob>
.then(currentJob => {
const apiBarcodes = currentJob.inventoryJob.history;
if (apiBarcodes.length > 0) {
this.setState({apiBarcodes});
}
this.setState({initialLoad: true});
}); // --> Promise<void>
};
}
So I am making assertions about the promises in each then
call above but those assertions are all validated by type inference with the exception of the initial type cast on the response value.
As further evidence, if we remove the type declaration from the getCurrentJobAPI
property of A
, flow will infer that its type is in fact Promise<void>
.
Bonus: simplifying with async
/await
. I've used several ESNext features above to shorten the code and make it a bit more pleasant, but we can leverage a specific feature, async
/await
to make it easier to understand control flow and types in Promise
based code.
Consider this revision.
// @flow
import React from 'react';
type CurrentJob = {
inventoryJob: Job,
inventoryJobDetails: JobDetails[]
}
export default class A extends React.Component<{currentJob:JobDetails}, any> {
getCurrentJobAPI = async () => {
const url = `dummy_url&job_id=${String(this.props.currentJob)}`;
const response = await fetch(url, {credentials: 'include'});
const json = await response.json();
const currentJob = (json: CurrentJob); // make the assumption explicit.
console.log(currentJob);
const {location, id, note: ref_note} = currentJob.inventoryJob;
const currentCodes = currentJob.inventoryJobDetails.map(({code, qty}) => ({
code,
qty
}));
this.setState({currentCodes, location, ref_note, id});
const apiBarcodes = currentJob.inventoryJob.history;
if (apiBarcodes.length > 0) {
this.setState({apiBarcodes});
}
this.setState({initialLoad: true});
};
}
Clearly, this is a void
function. It has no return
statements. However, as an async
function, it inherently returns a Promise
, just as it did when written as an explicit Promise
chain.
Note: void
is a construct that has been found useful in Flow and TypeScript to represent the semantic intent of function that do not return values but in reality such functions actually return undefined
because, well, this is JavaScript. Flow does not seem to recognize undefined
as a type, but under TypeScript, the function could equally be annotated as returning Promise<undefined>
. Irregardless, Promise<void>
is preferable thanks to the clarity of intent it provides.
Remarks: I worked through this using a bination of https://flow/try and the flow binary for Windows. The experience on Windows is really terrible and hopefully it will improve.
When chaining then's, the result will always be a promise.
When calling then
, the return value is another promise, otherwise chaining then's wouldn't have been possible.
You can see that easily by using console.log() surrounding the entire chain.
本文标签: javascriptFlow Types with Promises (Fetch39s)Stack Overflow
版权声明:本文标题:javascript - Flow Types with Promises (Fetch's) - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744951713a2634124.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论