代码之家  ›  专栏  ›  技术社区  ›  Patrick Kenny

当扩展数组类型并提供标准数组时,TypeScript不会抱怨

  •  1
  • Patrick Kenny  · 技术社区  · 1 年前

    在TypeScript中,我正在尝试扩展 Array 用于我的应用程序中的特殊情况。

    这是我的代码:( playground )

    enum FruitsEnum {
        Kiwi = "Kiwi",
        Pear= "Pear",
        DragonFruit = "DragonFruit",
    }
    
    class FruitArray extends Array<FruitsEnum | string> {
        constructor(fruit: FruitsEnum, ...rest: string[]) {
            console.log(`constructor: ${fruit}`);
            super(fruit, ...rest);
        }
    }
    
    const processFruit = (fruit: FruitArray) => {
        console.log('This is the fruit', fruit);
    }
    
    const main = () => {
        processFruit(['notAFruit']);
    }
    

    我不明白的是为什么TypeScript允许 processFruit(['notAFruit']) 。我指定了 processFruit() 采取 FruitArray ,但是我可以给它一个标准数组,它接受这个。为什么?

    1 回复  |  直到 1 年前
        1
  •  1
  •   jcalz    1 年前

    TypeScript的类型系统是 structural nominal 。如果两个类型在结构上相同,则TypeScript将它们视为相同的类型。如果你 extend 一个接口或类,而不添加任何新成员,则新接口或新类实例类型将被视为 与父类型相同 这可能导致令人惊讶的行为, as documented in the TypeScript Handbook

    在你的例子中,这意味着 FruitArray 被视为与相同类型 Array<FruitsEnum | string> ,顺便说一句,也是与 Array<string> 因为 FruitsEnum 是的子类型 string 。因此,在任何地方 水果阵列 需要,a string[] 就足够了。

    如果你想防止这种情况发生,最简单的方法是将一些成员添加到 水果阵列 在结构上与 字符串[] 。例如:

    class FruitArray extends Array<FruitsEnum | string> {
        prop = ""; // anything to structurally distinguish from Array
        constructor(fruit: FruitsEnum, ...rest: string[]) {
            console.log(`constructor: ${fruit}`);
            super(fruit, ...rest);
        }
    }
    
    const main = () => {
        processFruit(['notAFruit']); // error!
        // --------> ~~~~~~~~~~~~~
        // Argument of type 'string[]' is not assignable to parameter of type 'FruitArray'.
    }
    

    Playground link to code

    推荐文章