#How to make a parameter conditionally optional?

24 messages · Page 1 of 1 (latest)

leaden token
#

For example the following code almost works, the problem is that if the type is undefined it's still required (test(undefined)).

const symbol =

function test<Type>(param: if Type something ? required : not) {}

Is this possible and how?

#

How to make a parameter conditionally optional?

brisk mountain
#

overloads

solar heath
#

You can also use spread arguments:

plain siloBOT
#
declare function fn<T>(...args: T extends string ? [arg: 42] : []): void

fn<string>()
//
// Expected 1 arguments, but got 0.
fn<string>(42)
fn<number>()
fn<number>(42)
//         ^^
// Expected 0 arguments, but got 1.
leaden token
#

Thanks so much (had this problem so many times), I think overloads are easier to understand (it's for a library).

#

!resolved

#

I think I have to use spread arguments after all because it's for a class construtor.

solar heath
#

You can overload constructor as well.

leaden token
#

But the generic can't have a different type for each overload, at least this is how I did it:

const symbol = Symbol();

type Symbol = typeof symbol;

function test<Type extends Symbol>(param?: undefined): void;
function test<Type>(param: Type): void;
function test<Type = Symbol>(param: Type | undefined) {}
brisk mountain
#

sure it can, only one of them is instantiated

#

but since the first overload doesn't use its generic, it isn't inferrable

leaden token
#

I don't understand, the last example I gave works, what I meant is that I don't think I can do the same with a class construtor.

brisk mountain
#

oh, i missed a few messages, sorry

#

maybe show the issue you were having?

leaden token
#

It works now with Burrito's answer, I would prefer to overload because it's easier to understand (for the library users) but I don't think it's possible because classes have the generics types and constructor parameters in different places so I can't change one based on the other like with functions.

brisk mountain
#

what are you trying to achieve here exactly?

#

starting to sound like xyproblem

solar heath
#

But yeah, it does sound like an XY problem, you should probably explain what you are actually trying to achieve than your attempted solution.

leaden token
#

It's a router that has a state for each request that can be of a custom type, the default is Record<PropertyKey, unknown> and I want it so you don't have to pass an empty object in that case.

I got it working like this:

declare const DATA_BRAND: unique symbol;

type Default = Record<PropertyKey, unknown> & { [DATA_BRAND]: 'something' };

class Router<Data = Default> {
    constructor(...[data]: Data extends Default ? [] : [Data]) {}
}
leaden token
solar heath
#

I don't think that really works

#

You can still do:

const router = new Router<Default & { foo: string }>()
router.data.foo

Which will blow up at runtime.