【问题标题】:TypeScript not flagging incompatible genericsTypeScript 没有标记不兼容的泛型
【发布时间】:2018-07-20 17:12:51
【问题描述】:

我正在构建一个可插入的接口/类架构,以便“输​​出”可以插入“输入”。我很快发现,当我使用兼容的接口但使用不兼容的泛型时,TypeScript 不会引发任何警告或错误。有什么我做错了,我可以做更多的事情来强制正确检查,或者这根本不支持?打字稿 2.9.2

interface IValueA {
  fooA(): void;
}

interface IValueB {
  barB(): void;
}

interface ISomethingA<T> {
  goToB(thing: ISomethingB<T>): void;
}

interface ISomethingB<T> {
  goToA(thing: ISomethingA<T>): void;
}

interface ISomethingAS extends ISomethingA<string> {}
interface ISomethingAN extends ISomethingA<number> {}

interface ISomethingBS extends ISomethingB<string> {}
interface ISomethingBN extends ISomethingB<number> {}

export class SomethingA<T> implements ISomethingA<T> {
  public goToB(thing: ISomethingB<T>): void {
    console.log("SomethingA", "goToB", thing);
  }
}

export class SomethingAN implements ISomethingAN {
  public goToB(thing: ISomethingBN): void {
    console.log("SomethingA", "goToB", thing);
  }
}

export class SomethingAS implements ISomethingAS {
  public goToB(thing: ISomethingBS): void {
    console.log("SomethingA", "goToB", thing);
  }
}

export class SomethingB<T> implements ISomethingB<T> {
  public goToA(thing: ISomethingA<T>): void {
    console.log("SomethingA", "goToA", thing);
  }
}

export class SomethingBN implements ISomethingBN {
  public goToA(thing: ISomethingAN): void {
    console.log("SomethingA", "goToA", thing);
  }
}

export class SomethingBS implements ISomethingBS {
  public goToA(thing: ISomethingAS): void {
    console.log("SomethingA", "goToA", thing);
  }
}

const a = new SomethingA<IValueA>();
const b = new SomethingB<IValueB>();

const as = new SomethingAS();
const an = new SomethingAN();

const bs = new SomethingBS();
const bn = new SomethingBN();

a.goToB(b); // ISomethingA<IValueA> expects ISomethingB<IValueA> but accepts ISomethingB<IValueB>

as.goToB(bn); // ISomethingAS (ISomethingA<string>) expects ISomethingBS (ISomethingB<string>) but accepts ISomethingBN (ISomethingB<number>)
an.goToB(bs); // ISomethingAN (ISomethingA<number>) expects ISomethingBN (ISomethingB<number>) but accepts ISomethingBS (ISomethingB<string>)

【问题讨论】:

    标签: typescript class generics types interface


    【解决方案1】:

    如果你想要错误,你应该对ISomethingAISomethingB 内部的东西使用通用的T 参数。如果您只将它作为另一个泛型参数传递给其他东西而从未实际使用它,则不会出现错误,因为类型系统是结构化的并且类型是兼容的。

    正如它在FAQ 中所说:“一般来说,你永远不应该有一个未使用的类型参数。该类型将具有意想不到的兼容性(如此处所示)并且也将无法在函数中进行适当的泛型类型推断来电。”

    下面是给出您可能期望的错误的代码:

    interface IValueA {
      fooA(): void;
    }
    
    interface IValueB {
      barB(): void;
    }
    
    interface ISomethingA<T> {
        goToB(thing: ISomethingB<T>): void;
        t: T[];
    }
    
    interface ISomethingB<T> {
      goToA(thing: ISomethingA<T>): void;
        t: T[];
    }
    
    interface ISomethingAS extends ISomethingA<string> {}
    interface ISomethingAN extends ISomethingA<number> {}
    
    interface ISomethingBS extends ISomethingB<string> {}
    interface ISomethingBN extends ISomethingB<number> {}
    
    export class SomethingA<T> implements ISomethingA<T> {
      public goToB(thing: ISomethingB<T>): void {
        console.log("SomethingA", "goToB", thing);
      }
      t = [];
    }
    
    export class SomethingAN implements ISomethingAN {
      public goToB(thing: ISomethingBN): void {
        console.log("SomethingA", "goToB", thing);
      }
      t = [];
    }
    
    export class SomethingAS implements ISomethingAS {
      public goToB(thing: ISomethingBS): void {
        console.log("SomethingA", "goToB", thing);
      }
      t = [];
    }
    
    export class SomethingB<T> implements ISomethingB<T> {
      public goToA(thing: ISomethingA<T>): void {
        console.log("SomethingA", "goToA", thing);
      }
      t = [];
    }
    
    export class SomethingBN implements ISomethingBN {
      public goToA(thing: ISomethingAN): void {
        console.log("SomethingA", "goToA", thing);
      }
      t = [];
    }
    
    export class SomethingBS implements ISomethingBS {
      public goToA(thing: ISomethingAS): void {
        console.log("SomethingA", "goToA", thing);
      }
      t = [];
    }
    
    const a = new SomethingA<IValueA>();
    const b = new SomethingB<IValueB>();
    
    const as = new SomethingAS();
    const an = new SomethingAN();
    
    const bs = new SomethingBS();
    const bn = new SomethingBN();
    
    a.goToB(b); // error
    
    as.goToB(bn); // error
    an.goToB(bs); // error
    

    【讨论】:

      猜你喜欢
      • 2019-09-06
      • 2015-08-11
      • 2021-07-05
      • 1970-01-01
      • 1970-01-01
      • 2018-08-16
      • 1970-01-01
      • 2020-12-16
      相关资源
      最近更新 更多