I have an interface called Expression that through an OperatorExpression goes back to itself in like an infinite nesting structure.
Im passing in a generic that already has a generic and I would like to infer it.
I have the following interfaces:
type Expression<T, U = string> = (T extends Approval<U> ? Approval<U> : Condition<U>) | OperatorExpression<T, U>
interface OperatorExpression<U, T = string> {
operands: Expression<T, U>[]
// other stuff
}
interface Approval<T = string> {
approver: T
// other stuff
}
interface Condition<T = string> {
id: T
// other stuff
}
And then when I use the Expression with a generic that has a generic that is not string, I have to call it like this:
Expression<Approval<Types.ObjectId>, Types.ObjectId>
And I would like to be able to call it like this: Expression<Approval<Types.ObjectId>>
, basically infer the second generic based on the generic of the first generic.
In my little ts knowledge I imagined to do something like this, but it complains because "S" does not exist:
type Expression<T extends (Approval<S> | Condition<S>), U = S> = (T extends Approval<U> ? Approval<U> : Condition<U>) | OperatorExpression<T, U>
How could I do this? Thank you
edit
Since this is now solved thanks @Meowster, I'll put down here his solution integrated in my use case
type InferType<T> = T extends Approval<infer E> | WorkflowCondition<infer E> ? E : never;
type R<T> = InferType<T>
export type Expression<T, U = R<T>> =
| (T extends Approval<U> ? Approval<U> : T extends WorkflowCondition<U> ? WorkflowCondition<U> : WorkflowApproval<U>)
| OperatorExpression<T, U>
CodePudding user response:
type Expression<T extends Approval | Condition> = T | OperatorExpression<T>
interface OperatorExpression<T extends Approval | Condition> {
operands: Expression<T>[]
// other stuff
}
interface Approval<U = any> {
approver: U
// other stuff
}
interface Condition<U = any> {
id: U
// other stuff
}
type E = OperatorExpression<Approval<number>>
type O = E['operands'] // Expression<Approval<number>>[]
or use infer syntax
type InferType<T> = T extends Approval<infer E> | Condition<infer E> ? E : never;
interface Approval<T = string> {
approver: T
// other stuff
}
interface Condition<T = string> {
id: T
// other stuff
}
type R = InferType<Approval<number>> // R = number