Я был бы склонен избегать всех условных типов, так как компилятор не может рассуждать о них очень хорошо, и, похоже, они вам не нужны. Вместо type Foo<T> = T extends U ? F<T> : never
вы могли бы просто ограничить T
, например type Foo<T extends U> = Foo<T>
, что более просто для компилятора.
Решение здесь, вероятно, состоит в том, чтобы сделать getStyle()
универсальный в достаточном количестве параметров типа, чтобы компилятор понимал, что каждый параметр детализируется в объект и просматривает его свойства. Например:
const getStyle = <
K extends keyof Theme,
S extends keyof Theme[K],
M extends keyof Theme[K][S]
>(t: Theme, name: K, style: S, mod: M) => t[name][style][mod];
Здесь мы говорим, что t
имеет тип Theme
, что name
имеет некоторый универсальный тип K
, ограниченный keyof Theme
, что style
имеетнекоторый универсальный тип S
ограничен keyof Theme[K]
, а mod
имеет некоторый универсальный тип M
, ограниченный keyof Theme[K][S]
. Это позволяет t[name][style][mod]
компилироваться без ошибок, а тип возвращаемого значения getStyle()
выводится как Theme[K][S][M]
, что означает, что вывод будет также довольно строго типизирован:
const sm = getStyle(theme, "button", "margin", "sm"); // string
const lg = getStyle(theme, "form", "padding", "lg"); // string
Хорошо, надеюсь, чтопомогает. Удачи!
Ссылка на код