簡體   English   中英

TypeScript中的通用類型參數推斷優先級

[英]Generic type parameter inference priority in 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'。

我相信我已經確定了錯誤的起源,它是由編譯器在推斷泛型時引起的:泛型類型參數T是從initializer: (json: any) => T“T”推斷的initializer: (json: any) => T ,這意味着錯誤是由具有通用類型Kitty的JsonObject函數引起的, Cat顯然不能將其分配給它,因此在這種情況下,類裝飾器不能用於Cat

我希望它能夠從“返回”類型的target推斷出T ,這將解決我的問題。 我怎么能做到這一點?

當然,當我明確指定泛型類型參數時,它可以完美地工作(但這會帶來冗余信息):

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

如果你的意思是上面^它編譯得很好

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM