I have a component for making HTTP requests, and one of the properties ('address'
) should be optional, since I don't need it in one of the components where I call that function.
The way I did it before is to use the Partial utility type, but I want to be more specific and make a use of Pick.
Old version:
export type Trip = {
address: string
product: string
no: number
customer: string
}
export const usePostTrip = () => {
const queryClient = useQueryClient()
const mutation = useMutation(
async (data: Partial<Trip>) => { // This is achieved with Partial
const url = `${BASE_URL}/trip`
return axios.post(url, data ).catch((e) => console.log(e.message))
},
)
return mutation
}
Here is my current solution, which I believe is not the best one. Is there a better solution for this case?
export type Trip = {
address: string
product: string
no: number
customer: string
}
type tripWithoutAddress = Pick<
Trip, 'product'| 'no'
>
type tripsWithAddress = Pick<
Trip, 'product'| 'no' | 'address'
>
export const usePostTrip = () => {
const queryClient = useQueryClient()
const mutation = useMutation(
async (data: tripWithoutAddress | tripsWithAddress) => { // This is achieved with Pick
const url = `${BASE_URL}/trip`
return axios.post(url, data).catch((e) => console.log(e.message))
},
)
return mutation
}
CodePudding user response:
It's not clearly stated in your question, but it sounds like you want a version of Trip
where only the address
property is optional, and the others remain required. This can be achieved by omitting the address
property and then adding it back with an optional modifier by using an intersection type.
export type Trip = {
address: string;
product: string;
no: number;
customer: string;
};
export type TripWithOptionalAddress = Omit<Trip, "address"> & { address?: string; };
// All fields are required.
const trip: Trip = {
address: "123 TypeScript Ave",
product: "Stack Overflow",
no: 123,
customer: "Greg",
};
// `address` is missing.
const tripWithoutAddress: TripWithOptionalAddress = {
product: "Stack Overflow",
no: 123,
customer: "Greg",
};
// `address` is still allowed, if present.
const tripWithAddress: TripWithOptionalAddress = trip;
CodePudding user response:
I think Jimmy's answer is good, but:
If you ever change the address
property on Trip
(e.g. from string
to number
), you'll also have to manually change the optional version in order to maintain type consistency.
By using Pick
and Partial
, you can parametrically derive the type from Trip
: any changes to the address
property on Trip
will automatically be changed in the derived type, too:
type Trip = {
address: string;
customer: string;
no: number;
product: string;
}
type TripWithOptionalAddress = Omit<Trip, 'address'> & Partial<Pick<Trip, 'address'>>;
declare const t: TripWithOptionalAddress;
t.address // string | undefined