【问题标题】:Type 'never[]' is not assignable to type '...'类型 'never[]' 不能分配给类型 '...'
【发布时间】:2021-07-02 19:08:42
【问题描述】:

Type 'never[]' is not assignable to type '...'

由于这个随机错误,我无法在我的班级上初始化属性 items。我想将泛型类类型扩展到Array<string> 会确保该类型始终是字符串数组?

class MyClass<TItems extends Array<string>> {
    constructor() {
        this.items = [];
    }

    public items: TItems;
}

给我错误:

类型“字符串”不可分配给类型“TItems”。 “string”可分配给“TItems”类型的约束,但“TItems”可以用约束“string”的不同子类型实例化。ts(2322)

【问题讨论】:

  • 分享您的代码,而不是代码中错误屏幕截图的链接。
  • @Evert 好的,我更新了帖子。
  • 伟大的编辑。对于它的价值,它不是我下载的。

标签: typescript


【解决方案1】:

问题

您可能熟悉这样一个事实,即可以将子类型分配给超类型,但反之亦然。所以,在下面的代码和内联解释中——

class A extends Array<string> {
  public myProp!: string
}

// it is ok to assign a subtype to its supertype
// because subtype has atleast all those props/methods
// that a supertype has
declare const a1: A
const array1: Array<string> = a1

// it is an error to assign supertype to one of its subtype
// (until they are structurally same)
// because the supertype (array2) may have some missing props/methods
// (myProp in this case) that its subtype has.
declare const array2: Array<string>
const a2: A = array2

Playground

在您的代码中,TItemsArray&lt;string&gt; 的子类型,[] 的类型是 never[]

如果您使用 [] as Array&lt;string&gt; 对其进行了类型转换,则无法将超类型 (Array&lt;string&gt;) 分配给子类型 TItemsPlayground

如果你用[] as TItems 对它进行了类型转换,那么由于同样的原因,类型转换本身就是错误的。 Playground

解决方案

可以通过类型转换为错误来消除错误-

class MyClass<TItems extends Array<string>> {
    public items: TItems;

    constructor() {
        this.items = [] as unknown as TItems;
    }
}

Playground

但这可能会导致运行时错误,因为它不是“安全”的类型转换。

为避免运行时错误,正确的方法是使用 TItems 类的构造函数或返回 TItems 的函数而不是 = [] 来初始化 prop items。这将消除类型错误并确保不会出现运行时错误。两种方式都得到证明-

// if a passed TItems is supposed to class
// we pass that constructor of the class 
// constructor of `MyClass`
class MyClass<TItems extends Array<string>> {
    public items: TItems;

    constructor(ctor: new () => TItems) {
        this.items = new ctor();
    }
}

class MyArray extends Array<string> {
  private myProp!: string
}

const myClassVar = new MyClass(MyArray)

Playground

// if a passed TItems is supposed to be just a type
// we pass a function that will create that object of `TItems`
class MyClass<TItems extends Array<string>> {
    public items: TItems;

    constructor(fn: () => TItems) {
        this.items = fn();
    }
}

declare function createObject(): Array<string> & { myProp: string }

const myClassVar = new MyClass(createObject)

Playground

【讨论】:

    【解决方案2】:

    我认为您希望这样做:

    class MyClass<TItem extends string> {
        constructor() {
            this.items = [];
        }
    
        public items: TItem[];
    }
    

    问题是你说TItems 必须扩展字符串,这意味着this.items 也必须扩展字符串。

    鉴于您提到您想要一个字符串数组,这是我的最佳猜测。

    【讨论】:

    • 糟糕,我编辑问题时一定是打错字了。它应该扩展Array&lt;string&gt;
    • @Matt 你有什么理由不想采用我采取的方法吗?如果它总是一个数组,这可能更简单
    【解决方案3】:

    在类中全局声明数组

    class MyClass{
     never : any[] = [];
    
     constructor()
     {
      // this.
     } 
    
    }
    

    【讨论】:

    • 我很欣赏这个答案,但我特别问的是泛型类。
    猜你喜欢
    • 2020-07-29
    • 2022-11-14
    • 1970-01-01
    • 2021-08-08
    • 1970-01-01
    • 2018-11-03
    • 2021-06-09
    • 1970-01-01
    • 2022-08-14
    相关资源
    最近更新 更多