I heard that declaring optional types is bad in typescript.
In my app, there’s two functions that needs to call createPayment
.
createPayment
takes a payment
payload which is of type Payment
On the first function (onCreatePayment), firstName
, lastName
and contactNumber
shouldn’t be pass while on the second function (onCreateAnotherPayment), it needs to be pass. If I don’t pass firstName
, lastName
and contactNumber
in the 1st function, it complains because I’ve declare it as not optional in type.
What is the correct approach to this?
1st function
const onCreatePayment = () => {
...
try {
const { data } = await createPayment(
{
payment_link_id,
payment_method_provider,
payment_method_method,
custom_amount,
customer_details: {
noteToMerchant: notes,
},
},
);
return ...
} catch (error) {
...
}
};
2nd function
const onCreateAnotherPayment = () => {
...
try {
const { data } = await createPayment(
{
payment_link_id,
payment_method_provider,
payment_method_method,
custom_amount,
customer_details: {
noteToMerchant: notes,
firstName,
lastName,
contactNumber,
},
},
);
return ...
} catch (error) {
...
}
};
API
export const createPayment = (data: Payment, config?: ApiRequestConfig) => {
return api.post<PaymentResponse>(
`/payments`,
data,
config,
);
};
Type
export type Payment = {
payment_link_id: string;
payment_method_provider: string;
payment_method_method: string;
custom_amount: number;
customer_details: {
noteToMerchant: string;
firstName: string;
lastName: string;
contactNumber: string;
};
};
2
Answers
There are no hard rules on whether to avoid optional or not, so as long as it satisfies your requirement, you are good to go.
In the book Clean Code, the only time it mentioned about to avoid using optional is when passing an argument into a function unless it’s the very last argument for the function. And if there’s more than one optional properties needs to be passed into the argument of the function, consolidate them into an object and pass that single object as the last argument.
So to recap, there’s really no hard requirement to avoid an optional types as long as it fits your needs.
However, if you really want to avoid the optional types, my personal preference is to do what Redux does — introduce the initial state/data. So in the same file of your
createPayment
function, create an initial data for yourdata
like so —Then in your
createPaymen
function, apply the following —Now you won’t have to worry about declaring optional types.
Again, I want to emphasis that avoiding optional types is pointless as long as it fits your needs, and there are absolutely no hard rules in the Typescript world that you should do so.
Like other answers/comments suggested, having optional properties is not really a bad practice.
But if you are looking to avoid doing that, you can use the
Omit
utility to create a new type when you need to omit some of the properties you do not need, or use thePick
utility to create a new type for picking just the properties you need.Referencing: Typescript Utility Types