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

我有以下类装饰工厂接受初始化函数作为其参数。 在这个initializer函数中,我想返回一个对应于相关类类型(或派生类)的实例:

function JsonObject<T>(initializer: (json: any) => T) {
    return function (target: { new (...args: any[]): T }) {
        // ...
    }
}
@JsonObject(function (json) {
    return new Animal();
})
class Animal {
    name: string;
}

返回确切类的实例(如上所述)正常工作,但...

简洁版本

返回派生类的实例不会。 我可以返回一个基本实例,但不是派生的实例。 例如,我不能返回一个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的新类型的函数。 后者(返回的函数)显然是类装饰器本身。

编译器不允许我 - 例如 - 从这个initializer函数(或任何其他不匹配类型)返回一个字符串,这是它应该的。

与子类型有关的问题

但是,当使用子类型时,上述类型签名的行为完全相反:从initializer函数我可以返回一个基类型,但不是派生类型 - 在2步的中间类上使用时发生以下错误继承模式:

@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;
}

错误:输入'Cat'不可分配以键入'Kitty'。 'Cat'类型的属性'cutenessFactor'缺失。

我相信我已经指出了错误的起源,它是由编译器在推断泛型时造成的:泛型类型参数Tinitializer: (json: any) => T的“T”推断出来initializer: (json: any) => T ,这意味着错误是由具有通用类型Kitty的JsonObject函数引起的, Cat明显不能这样分配,因此在这种情况下类装饰器不能在Cat上使用。

我想这样做, T是从“返回”类型的target推断出来的,这可以解决我的问题。 我怎么能做到这一点?

当然,当我明确指定泛型类型参数时,它的工作原理是完美的(但是这带有冗余信息):

@JsonObject<Cat>(function (json) {
    return new Kitty(); // OK, since type 'Kitty' is assignable to type 'Cat'
})
class Cat extends Animal { }

你的意思是链接装饰者还是你的意思是:

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;
}

如果你的意思是上面的^,它编译得很好

链接地址: http://www.djcxy.com/p/43155.html

上一篇: Generic type parameter inference priority in TypeScript

下一篇: Type inference in TypeScript for curried function