Как печатать результаты итератора, используя генераторы в машинописи - PullRequest
1 голос
/ 04 мая 2020

Я использую машинопись, и я создал следующий код

function* myIter(): Iterator<number> {
    yield 3;
    yield 2;
    yield 1;
}

const iter: Iterator<number> = myIter();
const item:IteratorYieldResult<number> = iter.next();

DEMO

Выдает ошибку машинописи

enter image description here

Сообщая мне при наведении курсора, что это за ошибка

enter image description here

Я проверил, что именно next возвращает и нашел это определение интерфейса:

interface Iterator<T, TReturn = any, TNext = undefined> {
    // NOTE: 'next' is defined using a tuple to ensure we report the correct assignability errors in all places.
    next(...args: [] | [TNext]): IteratorResult<T, TReturn>;
    return?(value?: TReturn): IteratorResult<T, TReturn>;
    throw?(e?: any): IteratorResult<T, TReturn>;
}

И это тот момент, когда я заблудился, потому что мой итератор определен как Iteractor<number>, так что такое TReturn. С другой стороны, по умолчанию оно установлено на any, поэтому я думаю, что это необязательно, и я могу его опустить. Но по некоторым причинам это не работает таким образом с IteratorResult. Во всяком случае, некоторые рекомендации будут оценены?

Я не уверен, в чем проблема, но, возможно, кто-то может помочь мне с этим?

1 Ответ

2 голосов
/ 04 мая 2020

Как вы показали, метод итератора next() возвращает значение типа IteratorResult. Это определяется как:

type IteratorResult<T, TReturn = any> = IteratorYieldResult<T> 
  | IteratorReturnResult<TReturn>;

, объединение из IteratorYieldResult и IteratorReturnResult, сами определены , например:

interface IteratorYieldResult<TYield> {
    done?: false;
    value: TYield;
}

interface IteratorReturnResult<TReturn> {
    done: true;
    value: TReturn;
}

Это означает, что компилятор сообщает вам, что iter.next() возвращает либо IteratorYieldResult объект со свойством false / missing done и value типа number, или он возвращает объект IteratorReturnResult со свойством true done и value типа any.

Вы присваиваете это переменной типа IteratorYieldResult, и компилятор говорит вам: «подождите, это может быть не такого типа. Это может быть IteratorReturnResult ".

Теперь, так как вы сами написали генератор, вы знаете, что при первом вызове next() вы получите IteratorYieldResult, потому что есть три оператора yield до возврата из функции. Но это информация, которой система типов просто не обладает. Это так:

function foo(): number | string {
    return "hello";
}
const str: string = foo(); // error! number not assignable to string

Функция foo() возвращает либо number, либо string, в соответствии с сигнатурой типа. Вы можете сказать, что он всегда будет возвращать string, но компилятор не может этого сказать, потому что он просто смотрит на сигнатуру, а не углубляется в реализацию. И вот он жалуется: «эй, может быть str будет number во время выполнения, а не string, как вы заявляете».


Так что же «правильно» делать Вот? Я думаю, это зависит от того, что вы пытаетесь сделать. В этом игрушечном примере вы можете просто сказать компилятору, что вам не нужно беспокоиться и что вы уверены , чтобы получить IteratorYieldResult, а не IteratorReturnResult. И этот вид «сообщения» компилятору о том, что что-то имеет более узкий тип, чем он может проверить, выполняется с помощью утверждения типа :

const itemAsserted = iter.next() as IteratorYieldResult<number>; // okay

Или вы можете выполнить общую проверку где вы не утверждаете, что знаете, что выходит (что имеет смысл, если реализация myIter() может измениться, или если вы делаете iter.next() в al oop):

const itemSafe = iter.next();
// const itemSafe: IteratorResult<number, any>
if (!itemSafe.done) {
    itemSafe; // const itemSafe: IteratorYieldResult<number>
    itemSafe.value.toFixed(); // okay
}

Здесь мы просто позволяем компилятору сообщить нам, что iter.next() возвращает IteratorResult<number, any>. Затем мы берем это возвращаемое значение и проверяем , проверяя свойство done. Если это не true, то компилятор услужливо сузит результат до IteratorYieldResult<number> для вас. Вам не нужно ничего утверждать, потому что компилятор понимает тип проверки типов, выполненный выше; это потому, что IteratorResult является дискриминационным объединением , где можно проверить одно свойство (в данном случае done), чтобы выяснить, на какого члена объединения вы просматриваете.


Хорошо, я надеюсь, что это имеет смысл для вас и полезно. Удачи!

Детская площадка ссылка на код

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...