Home > Software engineering >  Typescript setter function with Partial
Typescript setter function with Partial

Time:03-04

I have some problems with typescript when using setter & Partial

Please help me

type Options = {
    param1: number;
    param2: number;
}

class MyClass {
    private _options: Options;
    
    get options(): Options {
        return this._options;
    }

    set options(newOptions: Partial<Options>) {
        this._options = {
            param1: newOptions?.param1 || 0,
            param2: newOptions?.param2 || 0,
        }
    }

    constructor(newOptions?: Partial<Options>) {
        // Type 'Partial<Options>' cannot be assigned to type 'Options'
        this._options = newOptions || {};
    }
}

Throw error:

Type 'Partial' cannot be assigned to type 'Options'

CodePudding user response:

You can define a default value for the options, then overwrite all properties that are actually provided as arguments to your methods:

TS Playground

type Options = Record<'param1' | 'param2', number>;

const defaultOptions: Options = { param1: 0, param2: 0 };

class MyClass {
  private _options: Options;
  
  get options(): Options {
    return {...this._options};
  }

  set options(newOptions: Partial<Options>) {
    this._options = {...defaultOptions, ...newOptions};
  }

  constructor(newOptions?: Partial<Options>) {
    this._options = {...defaultOptions, ...newOptions};
  }
}


// Example:

const c = new MyClass();
console.log(c.options); // { param1: 0, param2: 0 }

c.options = {param1: 2};
console.log(c.options); // { param1: 2, param2: 0 }

c.options = {param2: 1};
console.log(c.options); // { param1: 0, param2: 1 }

Compiled JS from the TS playground:

"use strict";
const defaultOptions = { param1: 0, param2: 0 };
class MyClass {
    constructor(newOptions) {
        this._options = { ...defaultOptions, ...newOptions };
    }
    get options() {
        return { ...this._options };
    }
    set options(newOptions) {
        this._options = { ...defaultOptions, ...newOptions };
    }
}
// Example:
const c = new MyClass();
console.log(c.options); // { param1: 0, param2: 0 }
c.options = { param1: 2 };
console.log(c.options); // { param1: 2, param2: 0 }
c.options = { param2: 1 };
console.log(c.options); // { param1: 0, param2: 1 }

CodePudding user response:


Consideration

Since we want to be able to set a type Patial<Options>(narrow) to a type Options(wider)

Of many ways and without having to do any design consideration, how about any of the following:-

Candidate 1. Make the properties optional in type Options which as of now are mandatory.

type Options = {
    param1?: number; // <--- Optional Property
    param2?: number; // <--- Optional Property
}

class MyClass {
    private _options: Options;
    
    get options(): Options {
        return this._options;
    }

    set options(newOptions: Partial<Options>) {
        this._options = {
            param1: newOptions?.param1 || 0,
            param2: newOptions?.param2 || 0,
        }
    }

    constructor(newOptions?: Partial<Options>) {
        this._options = newOptions || {};
    }
}

Candidate 2. Change the type of option property on the class to Partial<Options>.

type Options = {
 param1:  number;
 param2: number;
}

class MyClass {
 private _options: Partial<Options>; // <--- The instance member itself is of type Partial<Options>
 
 get options(): Partial<Options> {   //<<--- This Partial<Options> is reflected on the interface of the class
     return this._options;
 }

 set options(newOptions: Partial<Options>) {
     this._options = {
         param1: newOptions?.param1 || 0,
         param2: newOptions?.param2 || 0,
     }
 }

 constructor(newOptions?: Partial<Options>) {
     this._options = newOptions || {};
 }
}

WYSIWYG => WHAT YOU SHOW IS WHAT YOU GET

  • Related