【问题标题】:Type of an Array of interface depending of T接口数组的类型取决于 T
【发布时间】:2021-01-22 04:40:58
【问题描述】:

我有一个接口,它有一个依赖于 T 的函数,它可以从字符串或数字扩展。

interface IConstructorReg<T extends string | number> {
    constructor: new (...args: any[]) => BaseImportObj;
    check: (data: T, fileName: string) => boolean;
}

我想推送实现该接口的对象。

function checkFun1(data: string, fileName: string) {
    // Severals Checkers ...
    return true;
}
const objImp1: IConstructorReg<string> = { constructor: ASCReader, check: checkFun1 };

function checkFun2(data: number, fileName: string) {
    // Severals Checkers ...
    return true;
}
const objImp2: IConstructorReg<number> = { constructor: ASCReader, check: checkFun2 };

const b: Array<IConstructorReg<string | number>> = [];
b.push(objImp1); //  Type 'string | number' is not assignable to type 'string'.
b.push(objImp2); //  Type 'string | number' is not assignable to type 'number'.

。数组“b”的正确类型是什么?

【问题讨论】:

    标签: arrays typescript typescript-typings


    【解决方案1】:

    本质上这是一个方差问题,即IConstructorReg 的方差。由于T 在函数签名中作为参数出现,所以IConstructorRegT 中是逆变的。这意味着IConstructorReg&lt;string | number&gt; 不是IConstructorReg&lt;string&gt; 的基本类型,而是相反(逆变中的对数来自与T 指向相反方向的继承箭头,您可以阅读有关方差的更多信息在this回答)

    要使其正常工作,您可以执行以下两项操作之一。

    您可以将Array&lt;IConstructorReg&lt;string | number&gt;&gt; 更改为Array&lt;IConstructorReg&lt;string&gt; | IConstructorReg&lt;number&gt;&gt;,这意味着该数组可以包含IConstructorReg&lt;number&gt;IConstructorReg&lt;string&gt;。但是,当您使用数组中的项目时,您需要检查两者中的哪一个才能调用check,而目前您的界面无法在运行时执行此检查:

    const b: Array<IConstructorReg<string> | IConstructorReg<number>> = [];
    b.push(objImp1); 
    b.push(objImp2); 
    b[0].check(0, "") // Argument of type 'number' is not assignable to parameter of type 'never'.
    (b[0] as IConstructorReg<number>).check(0, "") // type assertion is an option 
    

    Playground Link

    另一种解决方案是使用方法语法而不是函数字段语法来定义check。这将使IConstructorRegT 中成为双变量。虽然这不需要类型断言或检查,但它本质上是类型不安全的,因为 stringnumber 将可传递给期望其中一个或另一个的对象:

    interface IConstructorReg<T extends string | number> {
        constructor: new (...args: any[]) => BaseImportObj;
        check(data: T, fileName: string): boolean;
    }
    
    const b: Array<IConstructorReg<string | number>> = [];
    b.push(objImp1); 
    b.push(objImp2); 
    b[0].check(0, ""); // Ok
    b[0].check("0", ""); // Also Ok
    
    

    Playground Link

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-26
      • 2018-07-02
      • 1970-01-01
      • 2017-11-04
      • 1970-01-01
      相关资源
      最近更新 更多