打字稿引用自己的类型在返回类型

时间:2019-01-04 12:05:06

标签: typescript

我有一个基类ApiModel:

class ApiModel {
    static async fetch (params = {}, Model = this, apiPath = this.apiPath): Promise<any[] | PaginatedResponse> {
        let { data } = await axios.get(apiPath, { params })
        return Model.transformResponse(data)
    }
}

以及从中继承的模型:

class User extends ApiModel {
}

Typescript不喜欢我的返回定义(any [])和变量类型User:

let users: User[] = await User.fetch() // Assigned expression type any[] | PaginatedResponse is not assignable to type User[]

如何在不显式使用any[]的情况下替换User[](基于扩展类,它必须是通用的)

1 个答案:

答案 0 :(得分:2)

您得到的错误不是由于any[]User[]引起的,它不是由于与PaginatedResponse的并集引起的。

any[]PaginatedResponse之间的联合,将无法分配给User[]。您需要使用类型保护来区分数组结果和PaginatedResponse

因此这将与any[]一起工作(因为any可分配给任何其他类型,包括User

let result = await User.fetch()
if(result instanceof Array) {
    const user: User[] = result;
}else {
    const paged = result;
}

话虽如此,您仍应避免使用any(如瘟疫IMO,如果您不知道该类型更喜欢unknown(有关未知与否,请参见here))< / p>

要以静态方法获取当前类的类型,可以将通用类型参数与this参数注释一起使用。

确切的解决方案可能取决于类是否为抽象类以及构造函数是否具有参数(派生类型是否具有不同的参数签名)。

以下解决方案适用于非抽象基类,并且派生类是否具有与基类相同的构造函数签名(或兼容)。

interface PaginatedResponse<T> {
    start: number;
    end: number;
    data: T[]
}
class ApiModel {
    static apiPath = ""
    static async fetch<T extends typeof ApiModel>(this: T, params = {}, Model = this, apiPath = this.apiPath): Promise<Array<InstanceType<T>> | PaginatedResponse<InstanceType<T>>> {
        return null!;
    }
}
class User extends ApiModel {
}

(async function (){
    let result = await User.fetch()
    if(result instanceof Array) {
        const user = result; // is User[]
    }else {
        const paged = result; // PaginatedResponse<User>
    }
})()

请注意,由于不确定该类型是什么,我在PaginatedResponse中填充了一个接口,如果该类型在您的控制之下,我将使其通用以反映返回的结果类型。