Какова подробная логика утверждения типа в машинописном тексте?

Я отношусь к type assertion как к чему-то вроде Hi Compiler, I know the type of this variable better than you. Just follow me!.

Но похоже, что у компилятора все еще есть своя логика для вывода типа. Например, предположим,

interface PM_MGEInfo {
    category: string;
    bid: string;
    cid?: string;
    labs?: { [key: string]: any };
}

Тогда 1 и 2 не проблема, но 3 выдает ошибку TS2352.

  1. function makeMgeInfo(bid: string): PM_MGEInfo {
        return <PM_MGEInfo>{
            bid
        };
    }
    
  2. function makeMgeInfo(bid: string): PM_MGEInfo {
        return <PM_MGEInfo>{
            bid,
            labs: {}
        };
    }
    
  3. function makeMgeInfo(bid: string): PM_MGEInfo {
        return <PM_MGEInfo>{
            bid,
            // error TS2352: Type '{ labs: { poi_id: string; }; bid: string; }' cannot be converted to type 'PM_MGEInfo'.
            // Property 'category' is missing in type '{ labs: { poi_id: string; }; bid: string; }'.
            labs: {a: 1}
        };
    }
    

Почему type assertion начинает проверять другие поля в 3? Кто-нибудь знает его подробную логику?


Обновлено: я создал задачу в Github Microsoft/TypeScript#23698.


person chinesedfan    schedule 25.04.2018    source источник
comment
Звучит как регресс.   -  person unional    schedule 25.04.2018
comment
Да, мне кажется это баг. Если вы объявляете переменную PM_MGEInfo и присваиваете ей {bid: 'o'}, она показывает ошибку, говоря, что category отсутствует. Это должно быть поведение в 1) и 2). Не знаю, почему это срабатывает только в случае 3).   -  person Oscar Paz    schedule 25.04.2018
comment
Похоже, что сигнатура индекса { [key: string]: any } вызывает ошибку. Предлагаю открыть тему.   -  person Estus Flask    schedule 25.04.2018


Ответы (3)


Ознакомьтесь со спецификацией 4.16 Type Assertions, которая вдохновлена на этот ответ:

В выражении утверждения типа формы ‹ T > e, e контекстуально типизируется (раздел 4.23) T, и результирующий тип e должен быть присваиваемым T, или T должен быть присваиваемым расширенной форме результирующий тип e, иначе возникнет ошибка времени компиляции.

Для случая 1 T очевидно присваивается e.

Для случая 2 расширенная форма e — это {bid: string, labs: Object}, которому можно присвоить T. Обратите внимание, что labs? можно присвоить Object (На самом деле я не уверен в этом, но это мое единственное возможное объяснение).

Для случая 3 ни одно из вышеперечисленных условий не выполняется.

person chinesedfan    schedule 30.05.2018

Я вижу два варианта. Либо используйте Partial<T>, либо any. При использовании любого из них ВЫ несете ответственность за то, чтобы все работало, поэтому используйте последний вариант.

Примеры обоих:

function makeMgeInfoWithPartial(bid: string): Partial<PM_MGEInfo> {
  // props are optional but only those defined by PM_MGEInfo are valid
  return {
    bid,
    labs: {a: 1}
  }
}

function makeMgeInfoWithAny(bid: string): PM_MGEInfo {
  return {
    bid,
    labs: {a: 1},
    whatever: 'also works'
  } as any
}
person kctang    schedule 25.04.2018
comment
Я согласен с вами, что эти параметры заставят его работать, но вопрос в том, ПОЧЕМУ это работает таким образом ... добавление дополнительного свойства labs не должно было вызывать ошибку. - person Titian Cernicova-Dragomir; 25.04.2018
comment
@TitianCernicova-Dragomir, ошибка TS2352 не была вызвана labs. Сообщение об ошибке говорит Property 'category' is missing in type. Без category этот тип был бы неполным. - person kctang; 25.04.2018
comment
category отсутствует в этом, а также в return <PM_MGEInfo>{ bid } , и это РАБОТАЕТ, только при добавлении labs все ломается.. - person Titian Cernicova-Dragomir; 25.04.2018
comment
Спасибо за разъяснение @TitianCernicova-Dragomir. Я не видел этого раньше. хм.. не знаю почему! надеюсь, что кто-то еще может. :-) - person kctang; 25.04.2018

Я думаю, что компилятор не распознает ваше значение {a: 1} как тип { [key: string]: any }, потому что если вы измените строку таким образом, ошибки компилятора не будет:

function makeMgeInfo(bid: string): PM_MGEInfo {
  return <PM_MGEInfo>{
    bid,
    labs: {a: 1} as {[key: string]: any}
  };
}

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

mylabs: {[key: string]: any} = {a: 1};

и вызовите его в своей функции:

makeMgeInfo(bid: string): PM_MGEInfo {
  return <PM_MGEInfo>{
    bid,
    labs: this.mylabs
  };
}

Поэтому я бы сказал, что компилятор не распознает определенный вами тип из поля labs. Сообщение об ошибке в этом случае очень вводит в заблуждение.

person ochs.tobi    schedule 25.04.2018