Reputation: 1130
I have an invoice that can be in the states New/Invoiced. I have a doInvoicing method that takes a New Invoice and return an Invoiced invoice. But I can't change the state of the invoice in my method, due to it being bound to the New state.
Currently I can only think of casting the input invoice to Invoiced. However, this leaves a hole in the type checking, as it does not verify that I set the invoice state to Invoiced. I am thinking the operation required for this must combine the steps of casting/setting the value (if possible).
doInvoicing(invoice: Invoice & { state: invoiceState.New }):
Invoice & { state: invoiceState.Invoiced } {
var invoiced = invoice as Invoice & { state: invoiceState.Invoiced };
invoiced.state = invoiceState.Invoiced; // This MUST happen, but unverified
return invoiced;
}
enum invoiceState {
New, Invoiced
}
Upvotes: 1
Views: 1317
Reputation: 1130
I have found a somewhat ok solution that avoids copying. Encapsulate the change in a "setProperty" method:
changeProp<V extends T[K], T, K extends keyof T>(obj:
{ [P in keyof T]: T[P] }, key: K, value: V): T & { [P in K]: V } {
obj[key] = value; // The required change is not verified, but at least only 1 copy for entire program
return obj as T & { [P in K]: V };
}
This has the problem that the returned type is only restricted in V in regard to V type, not the value passed in. It can be stated with explicit generic paramters though:
var invoiced: InvoicedInvoice = this.changeProp<invoiceState.Invoiced, Invoice, "state">(invoice, "state", invoiceState.Invoiced);
Now the issue is that all generic parameters must be stated, not just V. Preferably only V or none of the generic parameters should have to be stated.
Upvotes: 0
Reputation: 1075467
With the way you have it set up, I don't see a way to do it without creating a new invoice object (or, of course, fudging with type assertions or any
):
return {...invoice, state: InvoiceState.Invoiced};
Note that spread does just a shallow copy, which seems like it would be sufficient here, but...
Upvotes: 2