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