Typescript: помощь в вводе аргумента функции

#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>
}