带有承诺的流类型(获取' s)

时间:2017-11-20 19:17:07

标签: javascript flowtype

我创建了一个Fetch函数来使用JSON API并为JSON对象定义了类型。我对如何定义getCurrentJobAPI函数的返回类型感到困惑,因为之后我做了一堆.then()。返回值是最后一个.then()吗?在我的代码中,最后一个.then()是一个setState,那么该类型是什么?

    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 });
            })
    };

更新

虽然我理解我应该将Promise<type>定义为getCurrentJobAPI的返回值(请参阅Gilad的答案和评论),但我仍然不确定为什么我如果Fetch解析为JSON响应,则无法写Promise<CurrentJob>

[我根据loganfsmyth的重新推荐浓缩了我的.then()语句。]

以下是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
}

2 个答案:

答案 0 :(得分:2)

首先,免责声明,我是TypeScript用户,但我发现这个问题实际上适用于这两种语言并且答案相同。

  

我创建了一个Fetch函数来使用JSON API并为JSON对象定义了类型。我很困惑如何定义getCurrentJobAPI函数的返回类型,因为之后我做了一堆.then()。返回值是最后一个.then()吗?在我的代码中,最后一个.then()是一个setState,那么该类型是什么?

TL; DR:Promise<void>(见注释)。正如您所怀疑的那样,这实际上是承诺链中最后一个顶级.then的返回类型。

现在让我们深入挖掘一下

以下是您的示例,稍微重写以利用类型推断,而不是注释其接收方声明为any的回调参数。

顺便说一下,这些回调参数注释相当于不安全的隐式转换,或者在我们在TypeScript中调用它们时键入断言,它们与代码的形状有关。他们看起来像这样

declare function takesFn(fn: (args: any) => any): void;

所以我把它们最小化了,因为它们形成了一个微妙的陷阱

// @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>
    };
}

所以我在上面的每个then调用中对promise进行了断言,但这些断言都是通过类型推断验证的,除了响应值的初始类型转换。

作为进一步的证据,如果我们从getCurrentJobAPI的{​​{1}}属性中删除类型声明,则流程将推断其类型实际上是A

额外奖励:使用Promise<void> / async进行简化。我已经使用上面的几个ESNext功能来缩短代码并使其更加愉快,但我们可以利用特定功能await / async来更轻松地理解控制流和基于await的代码中的类型。

考虑这个修订版。

Promise

显然,这是一个// @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}); }; } 函数。它没有void个语句。但是,作为return函数,它本身会返回async,就像写入显式Promise链时一样。

注意: Promise是一个在Flow和TypeScript中有用的构造,用于表示不返回值的函数的语义意图,但实际上这些函数实际返回{{ 1}}因为,这是JavaScript。 Flow似乎不会将void识别为类型,但在TypeScript下,该函数同样可以注释为返回undefined。无论如何,由于其提供的意图清晰,undefined更为可取。

备注:我使用https://flow.org/try和Windows的流二进制文件组合完成了这项工作。 Windows上的体验非常糟糕,希望它会有所改善。

答案 1 :(得分:1)

当链接时,结果将永远是一个承诺。 在致电then时,返回值是另一个承诺,否则链接就不可能了。 您可以通过使用围绕整个链的console.log()轻松地看到它。