I assumed this block would do some type check for me.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// types

// snippet including only public info from LSPAY Payment API
type PaymentStepEvent = PaymentStepSetup | PaymentStepData

interface PaymentStepSetup {
step: PAYMENT_STEPS.SETUP
// ... some omitted fields
}

interface PaymentStepData {
step: PAYMENT_STEPS.DATA
// ... some omitted fields
}

enum PAYMENT_STEPS {
DATA = 'DATA',
SETUP = 'SETUP',
}
1
2
3
4
5
6
7
// event handling logic
let eventData: PaymentStepEvent
try {
eventData = JSON.parse(event.data)
} catch (e) {
// some error handling
}

The eventData: PaymentStepEvent looked like assigning the result of JSON.parse(event.data) to eventData would pass some type checking, but the sad truth is not.

Execute this block in playground:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
let data = '{"dog": "DATA"}' // or "{\"step\": \"DATA\"}"
let eventData: PaymentStepEvent
try {
eventData = JSON.parse(data)
console.log(eventData) // 👉 {"dog": "DATA"}
console.log(
'is recognized gateway message event: ' +
!!isRecognizedGatewayMessageEventData(eventData)
) // 👉 "is recognized gateway message event: false"
} catch (e) {
console.log('error parsing!')
}

function isPaymentStepEvent(eventData: PaymentStepEvent): boolean {
return eventData.step && Object.values(PAYMENT_STEPS).includes(eventData.step)
}

The isPaymentStepEvent serves as a type guard, which has to be implemented by user. TypeScript adds no type checking at run time at all.