Очевидное исправление, поменяйте местами порядок параметров типа, у вас не работает. Поэтому мы должны прибегнуть к менее очевидным исправлениям. Общая идея здесь такова: если вы не можете установить значение по умолчанию на то, что вам нужно, установите его на фиктивное значение, а затем, при использовании типа, проверьте значение фиктивного значения и используйте вместо него исходное желаемое значение по умолчанию. Так что Foo<T=Default<U>, U=X> ... T
становится чем-то вроде Foo<V=DefaultSigil, U=X> ... V extends DefaultSigil ? Default<U> : V
.
Вот один из способов сделать это:
type OrDefault<T> = [T] extends [never] ? IOptions<ICalls> : T;
class App<O extends IOptions<C> = never, C extends ICalls = ICalls>
extends BaseApp<OrDefault<O>> {
constructor(options: OrDefault<O>) {
super(options);
}
}
В этом случае мы используем never
в качестве фиктивного значения по умолчанию; если кто-то вручную не определит never
для O
, это безопасное значение для использования в качестве фиктивного. Затем OrDefault
проверяет, является ли его параметр never
или нет, и возвращает IOptions<ICalls>
, если это так.
Да, вы заметили, что проверка OrDefault
вместо [T] extends [never] ? ... : ...
T extends never ? ... : ...
. Причина, по которой я это сделал, заключается в том, чтобы избежать распределения условного типа по T
. Так как T
является «параметром обнаженного типа», когда вы его проверяете, как T extends never ? ... : ...
, компилятор попытается интерпретировать T
как объединение, разделить объединение на члены, выполнить условное выражение, а затем объединить результаты обратно в союз. Если вы передадите never
для T
, это будет выглядеть как «пустой союз», и результат всегда будет never
. Мы не хотим, чтобы OrDefault<never>
было never
, поэтому нам не нужны дистрибутивные условные типы. Самый простой обходной путь - не допустить, чтобы проверка была «голым» параметром типа, «одев» его в один кортеж. [T]
не разбивается на составляющие объединения, и поэтому OrDefault<never>
будет IOptions<ICalls>
по желанию.
И вместо использования O
позже мы используем OrDefault<O>
. Вы должны быть в состоянии убедиться, что это работает так, как вы хотите. Это неуклюже и запутанно, но это работает.
Хорошо, надеюсь, это поможет; удачи!
Детская площадка ссылка на код