Typescript Class 约束字符串

Typescript Class Constraint String

我尝试创建一个带有字符串约束的 class,但它在 get scale() 函数中给出了一个错误。

class Scaling<T extends string> {
  _scale = "";

  constructor(props: T) {
    this._scale = props;
  }

  setScale(scale: T) {
    this._scale = scale;
  }

  get scale(): T {
    return this._scale;
  }

Type 'string' is not assignable to type 'T'. 'string' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'string'. }

_scale 不应该是 T 类型吗?所以你会分配一个冒号 (:)

class Scaling<T extends string> {
  _scale: T;

  constructor(props: T) {
    this._scale = props;
  }

  setScale(scale: T) {
    this._scale = scale;
  }

  get scale(): T {
    return this._scale;
  }
}

用法为:

const scaling = new Scaling('Hello World')
console.log(scaling)

_scale 成员实际上应该是 T 类型。例如:

class Scaling<T extends string> {
  _scale = "" as T;

  constructor(props: T) {
    this._scale = props;
  }

  setScale(scale: T) {
    this._scale = scale;
  }

  get scale(): T {
    return this._scale;
  }
}

您应该从 get scale(): T.

中删除明确的 T return 类型

因为在初始化期间,T 推断为参数的文字类型。 考虑这个例子:

class Scaling<T extends string> {
    _scale = "";

    constructor(props: T) {
        this._scale = props;
    }

    setScale(scale: T) {
        this._scale = scale;
    }

    get scale(): T {
        return this._scale;
    }
}

// T infered as literal "hello"
const result = new Scaling('hello')

因此,当你想要 return T 时,它应该是 "hello".

在你的例子中,它不能是 "hello" 因为 _scale 的默认值是空字符串,因此它被推断为一个字符串。

let str = ''

// Type 'string' is not assignable to type '"hello"'
const sameCase = (): 'hello' => str 

您不能将 T 用作 _scale 的显式类型,因为 _scale 是可变的,而类型是不可变的。

这就是为什么 return Tget scale

输入不安全的原因

Even if i remove the T from the get scale, i still get an error when for const result = new Scaling("hello"); result.setScale("other")

我的错,没查到

为了使这个 class 通用,我们需要将推断的 T 从更具体的类型转换为更广泛的类型。

type Infer<T> = T extends infer R ? R : never

class Scaling<T extends string> {
  _scale = "";

  constructor(props: Infer<T>) {
    this._scale = props;
  }

  setScale(scale: T) {
    this._scale = scale;
  }

  get scale() {
    return this._scale;
  }
}

// T infered as literal "hello"
const result = new Scaling('hello') // ok

result.setScale('123') // ok

Playground