1

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
}

2 Answers 2

2

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...

Sign up to request clarification or add additional context in comments.

2 Comments

I liked the solution, the copy may be unneeded but I'll look more into ... operator.
Yeah, the fact it was a runtime copy to avoid a compile-time issue did bother me. :-) (BTW, ... isn't an operator, it's primary syntax. An operator can't do what it does.)
0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.