#Make method parameter optional depending on constructor parameter presence

19 messages · Page 1 of 1 (latest)

random forum
#

Hi all! Imagine I have the following class:

class MyClass {
  constructor(private prop?: string) {}

  method(prop?: string) {
    console.log(prop || this.prop);
  }
}

I want to achieve the following:
If prop is passed to the constructor, then method() could be called without any parameters.
If class was constructed without prop parameter, then method() must be called with prop argument.
Something like this:

const instance1 = new MyClass('prop');
instance1.method(); // <-- could be called without arguments

const instance2 = new MyClass();
instance2.method('prop'); // <-- argument is required

Is it possible to achieve it with TypeScript?
Thank you!

sweet citrus
hushed bloom
#

@random forum It's possible, but it involves some ugly conditional types:

halcyon pulsarBOT
#
class MyClass<T extends string | undefined> {
  constructor(private prop?: T) {}

  method(...args:  undefined extends T ? [prop: string] : [prop?: string]) {
    console.log(args[0] || this.prop!);
  }
}

const ex = new MyClass("foo");
ex.method()

const ex2 = new MyClass()
ex2.method()
//  ^^^^^^^^
// Expected 1 arguments, but got 0.
hushed bloom
#

I'd probably look for some other way to handle this, personally.

sweet citrus
#

Whoops I forgot about ! for a sec 😅

#

Still working on it

hushed bloom
#

I'm pretty sure you have to use tuples to conditionally make an argument optional. Setting it to undefined will make a mandatory arg that only allows undefined to be passed.

sweet citrus
#

Yeah just realised it's not the same.

hushed bloom
#

There's a lot of annoying little details - it's pretty hard to handle the MyClass<string | undefined> case correctly.

sweet citrus
#

Yours won't allow the parameter in the method though.

hushed bloom
#

It does?

random forum
#

@hushed bloom thanks, that works! I've tried with similar approach, but used T extends undefined instead of undefined extends T, and it didn't work. I'm curios the difference in this

halcyon pulsarBOT
#
retsam19#0

Preview:```ts
class MyClass<T extends string | undefined> {
constructor(private prop?: T) {}

method(
...args: undefined extends T
? [prop: string]
: [prop?: string]
) {
console.log(args[0] || this.prop!)
}
}

const ex = new MyClass("foo")
ex.method("bar")

const ex2 = new MyClass()
...```

sweet citrus
hushed bloom
#

TBH, it maybe shouldnt' be undefined extends T.

#

Like I said, it's probably not handling the MyClass<string | undefined> correctly.

#

Previous message was backwards: T extends undefined is the "exactly undefined" case, (it says T is a subtype of undefined, but undefined doesn't have subtypes other than itself)