Typescript函数重载不匹配

Typescript函数重载不匹配,typescript,Typescript,我遇到了函数重载的问题。编译器不断选择错误的签名,我想知道原因 下面是一个显示行为的代码段:。以下是代码段源代码供参考: class Query { } class QueryInsert extends Query { constructor(public readonly objects?: any[], public readonly collection?: any) { super(); } } class QueryUpdate extends Query { con

我遇到了函数重载的问题。编译器不断选择错误的签名,我想知道原因

下面是一个显示行为的代码段:。以下是代码段源代码供参考:

class Query { }
class QueryInsert extends Query {
    constructor(public readonly objects?: any[], public readonly collection?: any) { super(); }
}
class QueryUpdate extends Query {
    constructor(public readonly object?: any, public readonly collection?: any, public readonly conditions?: any) { super(); }
}
class QueryShowCollection extends Query { }
class QueryCollectionExists extends Query {
    constructor(public readonly collection: any) { super(); }
}
class QueryDescribeCollection extends Query {
    constructor(public readonly collection: any) { super(); }
}
class QueryCreateCollection extends Query {
    constructor(public readonly collection: any, public readonly columns?: any[], public readonly indexes?: any[]) { super(); }
}
class QueryDropCollection extends Query {
    constructor(public readonly collection: any) { super(); }
}

function execute(query: QueryInsert): 'insert'
function execute(query: QueryUpdate): 'update'
function execute(query: QueryShowCollection): 'show'
function execute(query: QueryCollectionExists): 'exists'
function execute(query: QueryDescribeCollection): 'describe'
function execute(query: QueryCreateCollection): 'create'
function execute(query: QueryDropCollection): 'drop'
function execute(query: Query): any {

}

const insert = execute(new QueryInsert());
const update = execute(new QueryUpdate());
const show = execute(new QueryShowCollection());
const exists = execute(new QueryCollectionExists(''));
const describe = execute(new QueryDescribeCollection(''));
const create = execute(new QueryCreateCollection(''));
const drop = execute(new QueryDropCollection(''));
意外行为来自末尾的常量<代码>插入应报告
插入
更新
更新

show
之后,每个常量报告
“show”
. 我知道编译器从
函数execute(query:QueryShowCollection):“show”
中为这些常量选择签名。如果我们向下移动这个签名(例如:在带有queryropcollection的签名下面),那么现在它是
函数execute(query:QueryCollectionExists):“exists”
,用于其余常量


显然我做错了什么。

问题是Typescript使用结构兼容性来确定类型兼容性。在函数签名解析的情况下,编译器将在定义中计算每个重载,以找到参数
查询
可从参数分配的第一个重载

由于
QueryShowCollection
没有成员,因此它在结构上与所有其他
Query*Collection
类型兼容,这就是为什么所有集合都会显示
show
。另外,
querydescriptioncollection
QueryCollectionExists
在结构上是相同的。您不能以区分两者的方式对重载进行排序

你有两个解决方案

  • 将重载从结构较复杂的重载排序到结构较不复杂的重载,以使编译器选择正确的重载
  • 添加私有字段以确保类之间的类型不兼容。该字段不必使用,只需存在即可
第一个解决方案不适用于您,因为您的某些类在结构上是相同的,所以第二个解决方案如下所示:

class Query { }
class QueryInsert extends Query {
    private type: 'insert';
    constructor(public readonly objects?: any[], public readonly collection?: any) { super(); }
}
class QueryUpdate extends Query {
    private type: 'update';
    constructor(public readonly object?: any, public readonly collection?: any, public readonly conditions?: any) { super(); }
}
class QueryShowCollection extends Query { 
    private type: 'show';
}
class QueryCollectionExists extends Query {
    private type: 'exists';
    constructor(public readonly collection: any) { super(); }
}
class QueryDescribeCollection extends Query {
    private type: 'describe';
    constructor(public readonly collection: any) { super(); }
}
class QueryCreateCollection extends Query {
    private type: 'create';
    constructor(public readonly collection: any, public readonly columns?: any[], public readonly indexes?: any[]) { super(); }
}
class QueryDropCollection extends Query {
    private type: 'drop';
    constructor(public readonly collection: any) { super(); }
}

function execute(query: QueryInsert): 'insert'
function execute(query: QueryUpdate): 'update'
function execute(query: QueryDescribeCollection): 'describe'
function execute(query: QueryCreateCollection): 'create'
function execute(query: QueryDropCollection): 'drop'
function execute(query: QueryShowCollection): 'show'
function execute(query: QueryCollectionExists): 'exists'
function execute(query: Query): any {

}

const insert = execute(new QueryInsert());
const update = execute(new QueryUpdate());
const show = execute(new QueryShowCollection());
const exists = execute(new QueryCollectionExists(''));
const describe = execute(new QueryDescribeCollection(''));
const create = execute(new QueryCreateCollection(''));
const drop = execute(new QueryDropCollection(''));

我建议使用泛型而不是重载。因为您需要返回一个依赖于类的字符串常量,所以将该常量作为字段是有意义的

class Query {
    readonly type: string;
}
class QueryInsert extends Query {
    readonly type = 'insert';
    constructor(public readonly objects?: any[], public readonly collection?: any) { super(); }
}
class QueryUpdate extends Query {
    readonly type = 'update';
    constructor(public readonly object?: any, public readonly collection?: any, public readonly conditions?: any) { super(); }
}
class QueryShowCollection extends Query {
    readonly type = 'show';
}
class QueryCollectionExists extends Query {
    readonly type = 'exists';
    constructor(public readonly collection: any) { super(); }
}
class QueryDescribeCollection extends Query {
    readonly type = 'describe';
    constructor(public readonly collection: any) { super(); }
}
class QueryCreateCollection extends Query {
    readonly type = 'create';
    constructor(public readonly collection: any, public readonly columns?: any[], public readonly indexes?: any[]) { super(); }
}
class QueryDropCollection extends Query {
    readonly type = 'drop';
    constructor(public readonly collection: any) { super(); }
}

function execute<T extends Query>(query: T): T['type'] {
    return query.type;
}

const insert = execute(new QueryInsert());
const update = execute(new QueryUpdate());
const show = execute(new QueryShowCollection());
const exists = execute(new QueryCollectionExists(''));
const describe = execute(new QueryDescribeCollection(''));
const create = execute(new QueryCreateCollection(''));
const drop = execute(new QueryDropCollection(''));
类查询{
只读类型:字符串;
}
类QueryInsert扩展了查询{
只读类型='insert';
构造函数(公共只读对象?:any[],公共只读集合?:any){super();}
}
类QueryUpdate扩展了查询{
只读类型='update';
构造函数(公共只读对象?:any,公共只读集合?:any,公共只读条件?:any){super();}
}
类QueryShowCollection扩展了查询{
只读类型='show';
}
类QueryCollectionExists扩展查询{
只读类型='存在';
构造函数(公共只读集合:any){super();}
}
类QueryDescription集合扩展了查询{
只读类型='描述';
构造函数(公共只读集合:any){super();}
}
类QueryCreateCollection扩展了查询{
只读类型='create';
构造函数(公共只读集合:any,公共只读列?:any[],公共只读索引?:any[]){super();}
}
类queryropcollection扩展了查询{
只读类型='drop';
构造函数(公共只读集合:any){super();}
}
函数执行(查询:T):T['type']{
返回query.type;
}
const insert=execute(new QueryInsert());
const update=execute(new QueryUpdate());
const show=execute(新QueryShowCollection());
const exists=execute(新QueryCollectionExists(“”));
const descripe=execute(新querydescription集合(“”));
const create=execute(新QueryCreateCollection(“”));
const drop=execute(新的queryropcollection(“”));

你说的“每一个常量报告
”是什么意思“
?在Typescript游乐场中,将鼠标悬停在剪断部分末尾的常量上。您将看到编译器对每一个的报告。感谢您编写的良好解释和示例。感谢您的建议。整个片段被剥离以展示我所经历的行为。在实际代码中,
execute
返回一个
Query*Result
对象,该对象对于每个
Query*
@MichaelGrenier都是不同的。我知道,当它不是一个静态原语时,通用方法需要某种类型的类型查找表,它最终将与重载列表一样长。