Определения Typescript - вложенные функции - PullRequest
1 голос
/ 12 марта 2019

Как указано ниже, скажем, у нас есть:

  1. функция r, которая объединяет несколько задач вместе
  2. и функция o, которая возвращает форму, подобную when(cb).map(cb)

каждый обратный вызов, передаваемый when или map, всегда должен принимать следующие 3 аргументы: S, A, C, где S и C определены в r, а A определены в o .

вот ссылка на площадку для машинописи , которая также показывает ошибку, которую я получаю.

Мой вопрос: Как я могу получить безопасную декларацию?

type Task<S, A, C> = <AA extends A>(s: S, a: AA, c: C) => any;
type Fn<S, A, C> = (s: S, a: A, c: C) => any;

const r = <S, C>() => ({
  tasks: (...tasks: Task<S, any, C>[]) => null,
});

const o = <T, A = { prop: T }>(type: T) => ({
  when: <S, C>(fp: Fn<S, A, C>) => ({
    map: <SS extends S, CC extends C>(fn: Fn<SS, A, CC>): Task<SS, A, CC> => (
      (s: SS, a: A, c: CC): any => (
        fp(s, a, c) ? fn(s, a, c) : s
      )
    ),
  }),
});

const result = r<2, 7>().tasks(
  o(44) // expect: cb(2, 44, 7)
    .when((s, a, c) => s + a.prop + c)
    .map((s, a, c) => s + a.prop + c),

  o(78) // expect: cb(2, 78, 7)
    .when((s, a, c) => s + a.prop + c)
    .map((s, a, c) => s + a.prop + c),

  // etc...
  // callback provided to `.map` is typesafe,
  // callback provided to `.when` is not,
);

imageS and C for the when(cb)">

Как видите, обратный вызов, предоставленный when, не является безопасным : Параметры S и C потеряны .

1 Ответ

1 голос
/ 12 марта 2019

Хм, помимо других проблем, похоже, что вы хотите вывод контекстуального типа , который не предусмотрен в языке. Вот как я бы порекомендовал набирать вещи:

type Fn<S, A, C> = (s: S, a: A, c: C) => any;

// allow tasks to be an array of Fn<S, any, C> 
const r = <S, C>() => ({
  tasks: <FF extends Fn<S, any, C>[]>(...tasks: FF) => null,
});
// it is concerning that S and C must be explicitly specified
// when calling r(); not sure how you will hook that up to runtime

// only make types generic if they need to be, 
// and declare close to their uses if you want them to be inferred
const o = <T>(type: T) => ({
  when: <S, C>(fp: Fn<S, { prop: T }, C>) => ({
    map: (fn: Fn<S, { prop: T }, C>) => (s: S, a: { prop: T }, c: C): any =>
      fp(s, a, c) ? fn(s, a, c) : s,
  }),
});

const result = r<2, 7>().tasks(
  o(44) // expect: db(2, 44, 7)
    // you need to annotate the s and c parameters in when().
    // The compiler does not try to infer S and C in o(44).when() contextually 
    // from the contextual parameter type of r<2.7>().tasks().
    .when((s: 2, a, c: 7) => s + a.prop + c)
    .map((s, a, c) => s + a.prop + c),

  o(78) // expect: db(2, 78, 7)        
    // alternatively you can specify S and C manually:
    .when<2, 7>((s, a, c) => s + a.prop + c)
    .map((s, a, c) => s + a.prop + c),
  // etc...
);

Вы изменили свои определения, так как я работал над этим, поэтому следующее может не совпадать с тем, что вы опубликовали. Короче говоря:

  • Заставить r().tasks() принять массив (возможно, кортеж ) значений Fn<S, any, C>, поэтому тот факт, что A второй задачи не совпадает с первой, не будет вызвать ошибку.

  • Не имеет универсального T, а также универсального A = {prop: T}. Я предполагаю, что A не предназначен для того, чтобы быть независимым от T, и вы пытаетесь использовать параметр типа по умолчанию для представления какого-либо назначения, но на самом деле это не работает. Вместо этого просто используйте T, а затем замените все экземпляры A на {prop: T}.

  • Имейте только столько общих типов, сколько вам нужно, и как можно ближе к нужному месту вывода. Я переместил S и C в o().when.

  • Наконец, контекстная типизация от параметра r<2.7>().tasks() до значений S и C в o().when() не происходит. Компилятор, вероятно, даже не пытается это сделать, поскольку логический вывод должен происходить на нескольких уровнях вызова функции. Единственный способ справиться с этим, по-видимому, состоит в том, чтобы повторно указать S и C, либо аннотируя параметры s и c обратного вызова, переданного в o().when(), либо вызывая o().when<2,7>().

Надеюсь, это поможет вам в правильном направлении. Удачи!

...