Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Typescript : generic not inferred

I’m new to Typescript, coming from Java/Kotlin. I have this script :

class RequestMessage<ResponseType> {}
class NewOrderRequestMessage extends RequestMessage<OrderFilled | OrderCancelled> {}

async function sendMessage<T>(requestMessage:RequestMessage<T>): Promise<T> {
    return new Promise<T>((resolve, reject) => {
        // ...
    })
}

(async () => {
    let requestMessage = new NewOrderRequestMessage()
    let result = await sendMessage(requestMessage)
})()

My problem is that result type is inferred as "unknown", while I expected it to be inferred to OrderFilled | OrderCancelled, as the parameter of sendMessage is a RequestMessage<OrderFilled | OrderCancelled>

Typically, in Java/Kotlin, the same logic makes result correctly inferred :

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

class Promise<T>()

open class RequestMessage<T> {}
class NewOrderRequestMessage : RequestMessage<Int>() {}

fun <T> sendMessage(requestMessage: RequestMessage<T>): Promise<T> {
    return Promise()
}

val requestMessage = NewOrderRequestMessage()
val result = sendMessage(requestMessage)

In this equivalent Kotlin script, result is inferred to Promise<Int>.

Why couldn’t it be in Typescript ? Due to this unknown type, Typescript doesn’t give me error at compilation when sendMessage returns a Promise of another type, giving me weird situations.. I expect response type to be OrderFilled or OrderCancelled, but sendMessage can actually resolve to a promise of a completely unrelated type without having any compilation error, which produces unexpected and unhandled exception at runtime.

>Solution :

TS is not strongly typed language, its type system is about shape only.
That said NewOrderRequestMessage is no longer a generic.
If you cast it to RequestMessage<OrderFilled | OrderCancelled> then inferring will work just fine:

interface OrderFilled {

}

interface OrderCancelled {

}

class RequestMessage<ResponseType> {}
class NewOrderRequestMessage extends RequestMessage<OrderFilled | OrderCancelled> {}
type RequestMessageWithOrder  = RequestMessage<OrderFilled | OrderCancelled>

async function sendMessage<T>(requestMessage:RequestMessage<T>): Promise<T> {
    return new Promise<T>((resolve, reject) => {
        // ...
    })
}

(async () => {
    let requestMessage: RequestMessageWithOrder = new NewOrderRequestMessage()
    let result = await sendMessage(requestMessage)
})()

Play with the code here

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading