Почему эта программа TypeScript компилируется?

#typescript

#typescript

Вопрос:

Давайте начнем с извинений за слишком общий вопрос, но я ломаю голову, как сузить его из-за непонимания того, что здесь происходит, поэтому буду корректировать на основе комментариев / ответов.

Я создал пример программы на TypeScript Playground, которая не должна компилироваться, но компилируется (используя последнюю версию TypeScript, v4.5.2 на момент написания этой статьи.) Я пытаюсь понять, почему это компилируется, чтобы понять, какие другие плохие программы могут проскользнуть мимо проверки типов и остаться незамеченными. Вот другая версия программы, которая показывает проблему во время выполнения. Есть ли какие-либо варианты, которые я пропустил, или что-нибудь, что я могу сделать, чтобы эта программа не проверяла тип?

Для удобства я также встроил рассматриваемую программу здесь:

 type Settings = { 'a': boolean; 'b': string }

function setSetting<K extends keyof Settings>(p: K, v: Settings[K]): void {}

// setSetting('a', 100) // good; it fails
setSetting('a', true); // good; compiles

function breakSetSetting(k: keyof Settings, v: boolean): void {
  setSetting(k, v);
}

breakSetSetting('b', true); // bad; it compiles!
 

Обновление: Согласно комментарию @crashmstr, использование generics for breakSettings приводит к тому, что программа не компилируется, однако мне до сих пор неясно, почему ей было разрешено компилироваться раньше.

Комментарии:

1. Если вы используете ту же подпись generics в breakSetSetting , то вы получаете ошибку компилятора, которую вы не можете просто передать в логическом v значении. Как бы то ни было, максимум, что знает компилятор, это то, что вызов setSetting there является a string | bool для второго параметра, и v для этого он «работает».

2. @crashmstr ага . Вероятно, вам следует написать это в качестве ответа.

3. Спасибо, я обновил вопрос, однако я все еще не уверен, почему предыдущей программе вообще удалось скомпилироваться

Ответ №1:

Когда вы определяете K , вы определяете, что это будет 'a' | 'b' (что есть keyof K ). Это означает, что v это будет Settings['a' | 'b'] то, что оценивается boolean | string как . Теперь, когда вы breakSetSetting передаете a boolean в setSetting , boolean находится в области действия boolean | string , заставляя компилятор пройти.

Комментарии:

1. Я думаю, что я добираюсь туда, однако я не понимаю, почему это все еще разрешено компилировать. Итак, чтобы резюмировать, мое понимание проблемы заключается в том, что when K is выбрано как объединение, Settings[K] также является объединением, и поскольку объединения не упорядочены, фактические значения в этих объединениях могут не совпадать. Редактировать: теперь я вижу, как компилируется первая программа. Интересно, вторая версия программы, которую я связал (которая показывает проблему во время выполнения), просто реализована с использованием проблем {...s, [p]: v} . Может быть, есть более безопасный способ сделать эту часть?