Home > Net >  Typescript : generic not inferred
Typescript : generic not inferred

Time:12-26

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 :

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.

CodePudding user response:

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

  • Related