函数可以返回许多类型的响应。如何在接收响应的函数中声明响应的类型?

时间:2019-01-30 13:52:39

标签: typescript

使用此类方法

async openProject(
    fileName: string, 
    force: boolean, 
    progress: boolean
) {
    const response = await this.request({
        type: 'request',
        cmd: 'open_project',
        payload: { value: fileName, force: force, progress: progress }
    });

    return {
        id: response['payload']['project_id']
    };
}

当我尝试访问响应中的有效负载属性时,我收到TypeScript警告:

  

[ts]元素隐式地具有“ any”类型,因为类型“ {}”没有   索引签名。

我习惯于在函数调用中声明参数的类型。但是在这种情况下,我应该如何声明响应的类型? this.requests返回的诺言可以做出几种不同的响应。

我也许应该:

  • 为每种请求类型创建一个响应类型,并
  • 具有this.request返回所有响应类型的并集

编辑:

这是我的失败的解决方案

export type CreateProjectResponse = {
    payload: {
        project_id: string;
    }
}

export type GetDevicesResponse = {
    payload: {
        devices: [];
    }
}

export type GenericResponse = GetDevicesResponse | CreateProjectResponse;

request(body: any) {
    const transactionId = this.newTransactionId();

    const requestMessage = JSON.stringify({
        ...body,
        trans_id: transactionId
    });

    if (this.logger) this.logger(requestMessage);

    return new Promise<GenericResponse>((resolve, reject) => {
        const timeoutTimer = setTimeout(() => {
            const timeoutMessage = 'Request timed out';
            if (this.logger) this.logger(timeoutMessage);
            reject(Error(timeoutMessage));
        }, this.maxTime);

        this.requestCallbacks[transactionId] = {
            resolver: resolve,
            rejecter: reject,
            timeoutTimer: timeoutTimer
        };
        this.socket.send(requestMessage);
    });
}

async createProject() {
    const response = await this.request({
        type: 'request',
        cmd: 'create_project',
    }) ;

    return {
        id: response['payload']['project_id']
    };
};

async getDevices() {
    const response = await this.request({
        type: 'request',
        cmd: 'get_devices',
    });

    return response['payload']['devices'].filter((device: DeviceResponse) => {
        return device['type'] === 'device';
    }).map((device: DeviceResponse) => {
        return {
            id: device['device_id'],
            name: device['name']
        };
    });
};

3 个答案:

答案 0 :(得分:2)

这可以通过函数重载轻松完成...

interface IRequest {
    type: 'request';
    cmd: 'create_project' | 'get_devices';
}

interface IResponse {
    id: string
}

interface CreateProjectRequest extends IRequest { cmd: 'create_project'; }
interface GetDevicesRequest extends IRequest { cmd: 'get_devices'; }

interface CreateProjectResponse extends IResponse { }
interface GetDevicesResponce extends IResponse { name: string }

function request(body: CreateProjectRequest) : CreateProjectResponse
function request(body: GetDevicesRequest) : GetDevicesResponce
function request<T extends IRequest>(body: T) : IResponse {
    return {} as IResponse;
}

var myCreateProjectResponse = request({ cmd: 'create_project', type: 'request' });
var myGetDevicesResponse = request({ cmd: 'get_devices', type: 'request' });

[DEMO]

答案 1 :(得分:0)

您可以尝试使request函数具有通用性:

function request<T = any>(): Promise<T> {
    //...
    return {} as Promise<T>;
}

interface MyData {
    prop: number;
}

async () => {
    const data = await request<MyData>();
    //data.prop - awailable in autocomplete
}

T = any设置默认类型

您可以在https://www.typescriptlang.org/docs/handbook/generics.html

上找到更多信息。

答案 2 :(得分:0)

我认为正确的解决方案是针对不同的可能答案类型使用用户定义的类型防护

示例:

    interface Project: {
     project_id: number
    }

    function isProject(data: any): data is TypeA {
      return data.hasOwnProperty 
        && data.hasOwnProperty(project_id)
        && typeof data.project_id === "number"
    }

这将使打字稿编译器知道您收到的数据确实属于项目类型。

    async openProject(
        fileName: string, 
        force: boolean, 
        progress: boolean
    ): number {
        const response = await this.request({
            type: 'request',
            cmd: 'open_project',
            payload: { value: fileName, force: force, progress: progress }
        });

        const payload = response.payload

        if (isProject(payload)) {
          return payload.project_id
        }
    }

您可以处理各种类型的结果,如果您没有成功针对已知类型验证有效负载,则应该抛出异常。

使用完整链接:

https://basarat.gitbooks.io/typescript/docs/types/typeGuard.html

https://github.com/epoberezkin/ajv

实现类型保护的一种好方法是使用ajv之类的json模式库。

https://spin.atomicobject.com/2018/03/26/typescript-data-validation/