Home > front end >  Typescript Class Constraint String
Typescript Class Constraint String

Time:09-17

I try to create a class with a string contraint but the it gives an error at the get scale() function.

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'. }

CodePudding user response:

You should remove explicit T return type from get scale(): T.

Because during initialization, T inferes as literal type of argument. COnsider this example:

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')

Hence, when you want to return T it should be "hello".

In your example, it can't be "hello" because default value of _scale is empty string and accordingly it is infered as a string.

let str = ''

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

You can't use T as an explicit type for _scale because _scale is mutable and types are immutable.

This is why it is unsafe to return T type from get 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")

My bad, did not check it.

In order to make this class generic we need to convert infered T from more specific type to more wider.

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

CodePudding user response:

The _scale member should really be of type T. For example:

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;
  }
}

CodePudding user response:

Shouldn't _scale be of type T? So you'd assign with a colon (:)

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;
  }
}

The usage would be:

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