Generics TypeScript中的泛型类型参数推断优先级

Generics TypeScript中的泛型类型参数推断优先级,generics,typescript,decorator,Generics,Typescript,Decorator,下面是接受初始值设定项函数作为参数的例子。在这个初始值设定项函数中,我想返回一个与所涉及的类类型(或派生类类型)对应的实例: 返回精确类的实例(如上所述)可以正常工作,但是 短版 返回派生类的实例不会导致错误。我可以返回基本实例,但不能返回派生实例。例如,我无法返回一个Cat: @JsonObject(function (json) { return new Cat(); // Error. }) class Animal{ name: string; } class Cat

下面是接受初始值设定项函数作为参数的例子。在这个
初始值设定项
函数中,我想返回一个与所涉及的类类型(或派生类类型)对应的实例:

返回精确类的实例(如上所述)可以正常工作,但是

短版 返回派生类的实例不会导致错误。我可以返回基本实例,但不能返回派生实例。例如,我无法返回一个
Cat

@JsonObject(function (json) {
    return new Cat(); // Error.
})
class Animal{
    name: string;
}

class Cat extends Animal {
    color: string;
}
。。。即使猫是动物。但是,我可以退回一只动物而不是猫(这是错误的,因为动物不一定是猫),因为猫:

@JsonObject(function (json) {
    return new Animal(); // OK, but it shouldn't be
})
class Cat extends Animal {
    color: string;
}

长版本 JsonObject装饰工厂
JsonObject
函数类似于具有泛型类型参数
T
的函数,它接受一个回调函数,返回一个
T
作为其参数,并返回一个函数,该函数接受一个新类型,返回一个
T
。后者(返回的函数)显然是函数本身

例如,编译器不允许我从这个
初始值设定项
函数(或任何其他不匹配的类型)返回字符串,这是应该的

子类型问题 但是,当使用子类型时,上述类型签名的行为方式正好相反:从
初始值设定项
函数中,我可以返回基类型,但不能返回派生类型——在两步继承模式的中间类上使用时,会发生以下错误:

@JsonObject(function (json) {
    // Test case: return a base type.
    return new Animal(); // OK, but it shouldn't be: an 'Animal' is not a 'Cat'
})
@JsonObject(function (json) {
    // Test case: return an exact corresponding type.
    return new Cat(); // OK, as it should be
})
@JsonObject(function (json) {
    // Test case: return a derived type.
    return new Kitty(); // <-- Error, but it should be OK, a Kitty *is* a Cat
})
class Cat extends Animal {
    color: string;
}

class Kitty extends Cat {
    cutenessFactor: number;
}

你的意思是连锁装饰店还是说:

function JsonObject<T>(initializer: (json: any) => T) {
    return function (target: { new (...args: any[]): T }) {
        return null;
    }
}


@JsonObject(function (json) {
    return new Foo();
})
class Foo {
    foo: string;
}

@JsonObject(function (json) {
    // Test case: return an exact corresponding type.
    return new Bar(); // OK, as it should be
})
class Bar extends Foo {
    bar: string;
}

@JsonObject(function (json) {
    // Test case: return a derived type.
    return new Baz(); // Ok
})
class Baz extends Bar {
    baz: string;
}
函数JsonObject(初始值设定项:(json:any)=>T){ 返回函数(目标:{new(…args:any[]):T}){ 返回null; } } @JsonObject(函数(json){ 返回新的Foo(); }) 福班{ foo:string; } @JsonObject(函数(json){ //测试用例:返回精确的对应类型。 返回new Bar();//按原样确定 }) 类栏扩展了Foo{ 酒吧:字符串; } @JsonObject(函数(json){ //测试用例:返回一个派生类型。 返回新的Baz();//确定 }) 类Baz扩展条{ baz:字符串; }

如果您指的是上面的^it编译很好

您是指链接装饰程序还是指:

function JsonObject<T>(initializer: (json: any) => T) {
    return function (target: { new (...args: any[]): T }) {
        return null;
    }
}


@JsonObject(function (json) {
    return new Foo();
})
class Foo {
    foo: string;
}

@JsonObject(function (json) {
    // Test case: return an exact corresponding type.
    return new Bar(); // OK, as it should be
})
class Bar extends Foo {
    bar: string;
}

@JsonObject(function (json) {
    // Test case: return a derived type.
    return new Baz(); // Ok
})
class Baz extends Bar {
    baz: string;
}
函数JsonObject(初始值设定项:(json:any)=>T){ 返回函数(目标:{new(…args:any[]):T}){ 返回null; } } @JsonObject(函数(json){ 返回新的Foo(); }) 福班{ foo:string; } @JsonObject(函数(json){ //测试用例:返回精确的对应类型。 返回new Bar();//按原样确定 }) 类栏扩展了Foo{ 酒吧:字符串; } @JsonObject(函数(json){ //测试用例:返回一个派生类型。 返回新的Baz();//确定 }) 类Baz扩展条{ baz:字符串; }

如果您是指上面的^it compiles fine

是的,我是指单独使用,尽管关于类类型,我相信TypeScript编译器不识别类装饰器。除非我遗漏了什么,否则这并不重要。问题是
JsonObject
中的泛型类型参数
T
是从
初始值设定项
函数返回的值推断出来的,而不是从
目标
构造函数返回的值推断出来的。这可以很好地编译。不是吗?确实是这样。但是,如果要在应用于
Foo
的装饰器中返回
Bar
的实例,则会出现错误。这是因为编译器如何根据返回的内容推断出
JsonObject
的泛型类型。是的,我的意思是单独使用,尽管关于类类型,我相信TypeScript编译器不识别类装饰器。除非我遗漏了什么,否则这并不重要。问题是
JsonObject
中的泛型类型参数
T
是从
初始值设定项
函数返回的值推断出来的,而不是从
目标
构造函数返回的值推断出来的。这可以很好地编译。不是吗?确实是这样。但是,如果要在应用于
Foo
的装饰器中返回
Bar
的实例,则会出现错误。这是由于编译器如何根据返回的内容推断出
JsonObject
的泛型类型。
function JsonObject<T>(initializer: (json: any) => T) {
    return function (target: { new (...args: any[]): T }) {
        return null;
    }
}


@JsonObject(function (json) {
    return new Foo();
})
class Foo {
    foo: string;
}

@JsonObject(function (json) {
    // Test case: return an exact corresponding type.
    return new Bar(); // OK, as it should be
})
class Bar extends Foo {
    bar: string;
}

@JsonObject(function (json) {
    // Test case: return a derived type.
    return new Baz(); // Ok
})
class Baz extends Bar {
    baz: string;
}