【问题标题】:Type 'Extract<keyof T, string>' cannot be used to index type 'this'类型 'Extract<keyof T, string>' 不能用于索引类型 'this'
【发布时间】:2021-08-04 16:15:49
【问题描述】:

父类方法更新子类的属性,但我收到这些错误消息。我该如何解决这个问题。

index.ts 代码:

class A {
  animate<
    K extends keyof this,
    T extends {
      [key in K]: this[key] extends number ? this[key] : never
    }
  >(props: Partial<T>) {

    const initialValue: Partial<T> = {}
    const changeValue: Partial<T> = {}

    for (let key in props) {
      initialValue[key] = this[key]
      changeValue[key] = props[key] - this[key]
    }

    // ...
  }
}

class B extends A {
  width: number
  heigth: number
  name: string
  constructor() {
    super();
    this.heigth = 20
    this.width = 20
    this.name = 'B'
  }
}

const b = new B();

b.animate({
  width: 40,
  heigth: 40
})

错误信息:

/project/app/index.ts(13,27) 中的错误 TS2536:类型“Extract”不能用于索引类型“this”。

/project/app/index.ts(14,7) 中的错误 TS2322:类型 'number' 不可分配给类型 'T[Extract] |未定义'。

/project/app/index.ts(14,26) 中的错误 TS2362:算术运算的左侧必须是“any”、“number”、“bigint”类型或枚举类型。

/project/app/index.ts(14,39) 中的错误 TS2536:类型“Extract”不能用于索引类型“this”。

【问题讨论】:

    标签: typescript


    【解决方案1】:

    首先,class AthisB 一无所知。

    class A 中的this 只有一个方法animate

    我认为你应该在B 类中声明animate 属性。 您是否可以控制 A 类? 这行[key in K]: this[key] extends number ? this[key] : never 不会以您期望的方式工作。

    AB 都有不同的 this 上下文。

    考虑这个例子:

    
    class A {
      animate<
        K extends keyof this,
        T extends {
          [key in K]: number
        }
      >(this: Record<string, T[Extract<keyof T, string>]>, props: T) {
    
        const initialValue: Partial<T> = {}
        const changeValue: Record<string, number> = {}
    
        for (let key in props) {
          initialValue[key] = this[key]
          changeValue[key] = props[key] - this[key]
        }
    
        // ...
        return {initialValue, changeValue}
      }
    }
    
    class B extends A {
      width: number
      heigth: number
      name: string
    
      constructor() {
        super();
        this.heigth = 20
        this.width = 20
        this.name = 'B'
      }
    }
    const b = new B();
    
    const result = b.animate({ // <-------------------- Error
      width: 40,
      heigth: 40
    })
    

    “B”类型的“this”上下文不可分配给“Record”类型的方法“this”。 类型“B”中缺少索引签名

    虽然类实现中没有错误,但您不能使用 A 的上下文调用 b

    如果您不想更改继承模型,可以使用以下代码作为解决方法:

    interface Indexed {
      [prop: string]:
      | number
      | string
      | (<K extends keyof this,
        T extends {
          [key in K]: number
        }>(props: T) => void)
    }
    
    type Values<T> = T[keyof T]
    
    class A {
      [prop: string]:
      | number
      | string
      | (<K extends keyof this,
        T extends {
          [key in K]: number
        }>(props: T) => void)
    
      animate<
        Keys extends PropertyKey,
        Value extends number,
        Props extends Record<Keys, Value>
      >(props: Props) {
    
        const initialValue: Indexed = {}
        const changeValue: Indexed = {}
    
        for (let key in props) {
          initialValue[key] = this[key]
          changeValue[key] = props[key] - (this[key] as number)
    
          // ...
        }
      }
    }
    
    class B extends A {
      width: number
      heigth: number
      name: string
    
      constructor() {
        super();
        this.heigth = 20
        this.width = 20
        this.name = 'B'
      }
    }
    const b = new B();
    
    const result = b.animate({
      width: 40,
      heigth: 40
    })
    

    Playground

    附:尽量避免 TypeScript 中的突变。

    请参阅my article 和相关答案:[firstsecondthirdTS improvement]

    【讨论】:

      猜你喜欢
      • 2019-11-17
      • 1970-01-01
      • 2017-05-23
      • 1970-01-01
      • 2020-01-02
      • 2021-12-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多