#typescript #types #type-hinting
#typescript #типы #подсказка типа
Вопрос:
Я написал небольшую библиотеку, и теперь я пытаюсь добавить к ней поддержку типов путем создания пользовательских общих файлов.ts.
Чтобы привести пример (вызывается моя библиотека layerCompose
):
const C = layerCompose(
{
_($) { /* function body */ },
execute($) { /* function body */ }
}
)
const c = C()
c._()
Вы заметите, что обе _
execute
функции и принимают параметр $
.
Этот параметр (в нашем примере) представляет собой объект со _
execute
свойствами и (аналогично this
свойствам внутри класса)
Итак, я хотел бы добавить поддержку типов к этому $
параметру. Экспериментируя, я обнаружил, что наличие этого определения внутри моего общего файла.ts обеспечивает поддержку типов в _
функции.
export function layerCompose<
T extends [
A extends {}
? {
_($: {test: () => void})
}
: never
]
, A
>(...layers: T): lcConstructor<Spread<T>>
Другими словами, Webstorm может видеть, что $
параметр в _
функции имеет тип {test: () => void}
Очевидно, это не то, что я ищу. Однако изменение подписи на (что мне кажется правильным)
export function layerCompose<
T extends [
A extends {}
? {
[K in keyof A]: ($: {test: () => void}) => any
}
: never
]
, A
>(...layers: T): lcConstructor<Spread<T>>
и Webstorm теряет возможность определить, что $
это объект со свойствами _
и execute
.
РЕДАКТИРОВАТЬ: включен пример на typescript playground. В нем отсутствует возвращаемый тип (нетривиальный для быстрой настройки), но в остальном дает представление о том, что layerCompose
примерно делает.
ПРАВКА 2:
Продолжая играть, упростив сценарий до 1 параметра, это работает:
export function layerCompose<L1>(l1: {_: ($: {test: () => void}) => void} amp; L1): void
тем не менее, это не:
export function layerCompose<L1>(l1: {[K in keyof L1]: ($: {test: () => void}) => void} amp; L1): void
Комментарии:
1. Как
A
решается и почему он не используется в сигнатуре функции? Вы должны написать полностью воспроизводимый пример вашей проблемы. typescriptlang.org/play было бы желанным2. Приведенные вами примеры ввода
layerCompose
всегда приводят кT = never
. Вы уверены, что они используются? Webstorm, возможно, неправильно распознает ваши файлы объявлений.3. добавлен пример @GuerricP.
4. @Olian04 я довольно усердно следил за тем, чтобы обновления моих общих файлов распространялись. Я могу видеть, когда Webstorm собирает подписи и когда он терпит неудачу, когда я экспериментирую.
Ответ №1:
Это то, что вы ищете?
export function layerCompose(...layers: Layer[]): lcConstructor<Spread<T>>;
Поскольку вы не определили ни lcConstructor
того, ни Spread
другого, я не могу сделать никаких реальных предположений относительно того, каким layerCompose
должен быть возвращаемый тип. Итак, для целей этого ответа эти типы были заменены типом идентификатора.
// See playground below
type ComposedLayer = {
_(): void;
execute(): void;
}
type Layer = {
_(v: Layer): void;
execute(v: Layer): void;
}
/* dummy type */ type lcConstructor<T> = ComposedLayer;
/* dummy type */ type Spread<T> = T;
declare function layerCompose(...layers: Layer[]): lcConstructor<Spread<Layer>>;
const C = layerCompose(
{
_($) {},
execute($) {
$._({
_($) {},
execute($) {}
})
}
}
);
C._();
Комментарии:
1. Взгляните на пример игровой площадки, который я предоставил. Проблема в том, что я не знаю форму
Layer
заранее.
Ответ №2:
Согласно личному опыту, сначала найдите что-то как универсальный тип, чтобы избежать циклических зависимостей. Пожалуйста, проверьте следующие определения.
type Layer<K extends string> = Partial<Record<K, ($: Record<K, Function>) => void>>
function layerCompose<K extends string>(...layers: Layer<K>[]): Record<K, Function>
// ignore how do you implement to match types
return {} as Record<K, Function>
}