I was developing a typescript project where I came across a situation that I'd like to get type inference and completion for the second argument data
of a function which depends on the first argument type
of the function.
Here is the example type
enum MessageType {
FOO = "FOO",
BAR = "BAR",
BAZ = "BAZ",
}
interface DataFoo {
type: MessageType.FOO
payload: string
}
interface DataBarOrBaz {
type: MessageType.BAR | MessageType.BAZ
name: string
age: number
}
type Data = DataFoo | DataBarOrBaz
This is the function I am developing and I would like to have autocomplete for the data
parameter
function emit<T extends MessageType>(type: T, data: ???) {}
The expected result is like this
emit(MessageType.FOO, {
payload: "hello world"
// with autocomplete for payload in DataFoo
})
emit(MessageType.BAR, {
name: "hello"
age: 18
// with autocomplete for name and age in DataBarOrBaz
})
emit(MessageType.BAZ, {
name: "hello",
age: 18
// with autocomplete for name and age in DataBarOrBaz
})
However when I try to achieve the intended result with the Extract
utility type in typescript, it doesn't work for the interfaces that the type
field is a union of MessageType
function emit<T extends MessageType>(type: T, data: Omit<Extract<Data, {type: T}>, "type">) {}
emit(MessageType.FOO, { // the type for data becomes Omit<DataFoo, "type">
payload: "hello world"
// works as intended
})
emit(MessageType.BAR, { // the type for data becomes Omit<never, "type">
// expecting the type to be Omit<DataBarOrBaz, "type">
})
emit(MessageType.BAZ, { // the type for data becomes Omit<never, "type">
// expecting the type to be Omit<DataBarOrBaz, "type">
})
Is there any way to achieve the goal using typescript v5?