thorn0
thorn0

Reputation: 10387

TypeScript: check that the required properties of an argument are defined before passing it to a function call

This doesn't compile (playground):

function myFunction(params: {
    a: Date,
    b?: Date
}) {
    if (params.b) {
        myFunctionInternal(params); // ERROR!
    }
}

function myFunctionInternal(params: {
    a: Date,
    b: Date
}) {}

Is there a more elegant workaround than params as any?

Upvotes: 2

Views: 162

Answers (2)

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 249466

The problem is that the type guard impacts just the type of the field (params.b will have the undefined removed) not the type of whole object (param will continue to have the type { a: Date, b?: Date })

Not sure I would call it more elegant, but we can create a type guard that removes the undefined from a type field:

type RemoveOptionalFromField<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>> & { [P in K]-?: T[P] }

function notNull<T, K extends keyof T>(o: T | RemoveOptionalFromField<T, K>, key: K) : o is RemoveOptionalFromField<T, K> {
    return !!o[key];
}

function myFunction(params: {
    a: Date,
    b?: Date
}) {
    if (notNull(params, 'b')) {
        params.b.getDate()
        myFunctionInternal(params);
    }
}

We could even create a version that takes any number of keys:

function allNotNull<T, K extends keyof T>(o: T | RemoveOptionalFromField<T, K>, ...keys: K[]) : o is RemoveOptionalFromField<T, K> {
    return keys.every(k => !!o[k]);
}
function myFunction(params: {
    a?: Date,
    b?: Date
}) {
    if (allNotNull(params, 'b', 'a')) {
        params.b.getDate()
        myFunctionInternal(params);
    }
}

Upvotes: 4

Muhammed Albarmavi
Muhammed Albarmavi

Reputation: 24406

the error message said property 'b' is optional in type '{ a: Date; b?: Date; }' but required in type '{ a: Date; b: Date; }'

It can be solve like this

myFunctionInternal(params as {a,b}); 

or

myFunctionInternal({a:params.a ,b:params.b});

Upvotes: 2

Related Questions