带有 Promise 的流类型(Fetch)

Avr*_*zky 4 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 });
            })
    };
Run Code Online (Sandbox Code Playgroud)

更新

虽然我知道我应该定义为(参见GiladPromise<type>的答案和评论)的返回值,但我仍然不确定为什么如果 Fetch 解析为 JSON 响应我就无法编写。getCurrentJobAPIPromise<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
}
Run Code Online (Sandbox Code Playgroud)

Alu*_*dad 5

首先,免责声明,我是 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;
Run Code Online (Sandbox Code Playgroud)

所以我尽量减少这些,因为它们形成了一个微妙的陷阱

// @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>
    };
}
Run Code Online (Sandbox Code Playgroud)

因此,我对上面每个调用中的承诺做出断言then,但这些断言都是通过类型推断进行验证的,除了响应值上的初始类型转换之外。

getCurrentJobAPI作为进一步的证据,如果我们从的属性中删除类型声明A,flow 将推断它的类型实际上是Promise<void>

奖励:用async/简化await。我在上面使用了几个 ESNext 功能来缩短代码并使其更令人愉快,但我们可以利用特定功能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});

    };
}
Run Code Online (Sandbox Code Playgroud)

显然,这是一个void函数。它没有任何return声明。但是,作为一个async函数,它本质上返回 a Promise,就像编写为显式链时一样Promise

注意: void是一种在 Flow 和 TypeScript 中非常有用的构造,可以表示不返回值的函数的语义意图,但实际上此类函数实际上会返回undefined,因为这是 JavaScript。Flow 似乎无法识别undefined为类型,但在 TypeScript 下,该函数同样可以注释为 returns Promise<undefined>。无论如何,Promise<void>由于它提供了明确的意图,因此更可取。

备注:我使用https://flow.org/try和适用于 Windows 的流二进制文件的组合来完成此操作。Windows 上的体验真的很糟糕,希望能有所改善。