TypeScript: сужение типа: утверждать не неопределенным и, следовательно, исключать из типа - PullRequest
0 голосов
/ 30 апреля 2020

Обе эти строки сообщают об ошибке «Возможно, объект не определен» в _e[k]:

obj[k] = typeof _e[k] === "undefined" ? "" : _e[k].toString();
obj[k] = _e[k] === undefined ? "" : _e[k].toString();

_e[k] представляет собой объединение многих типов, поэтому приведение типов вручную не применимо. Как мне избавиться от ошибки?

update : Таким образом, в более общем смысле мой вопрос можно сформулировать так: есть ли способ сузить тип переменной путем проверки на указать c типы, которые следует исключить?

минимальный пример:

class test {
    a!: string;
    b?: number;
}
const t: test = { a: "hi", b: 2 };
for (const k of Object.keys(t) as Array<keyof test>) {
    console.log(t[k] == undefined ? "LOL" : t[k].toString());
}

Ответы [ 2 ]

1 голос
/ 30 апреля 2020

Существует давняя ошибка / проблема, из-за которой TypeScript не выполняет анализ потока управления для сужения типа свойства, если ключ свойства является переменной: microsoft / TypeScript # 10530 ; это не было решено, потому что исправление наложило большое снижение производительности. В вашем случае это означает, что проверка типа защиты на _e[k] не повлияет на последующее использование _e[k].

. Мой рекомендуемый обходной путь для этого - присвоить свойству доступ к индексу новую переменную и проверить это:

const ek = _e[k]; // new variable
obj[k] = typeof ek === "undefined" ? "" : ek.toString(); // no error now

Новая переменная ek применяет обычный анализ типа потока управления, и ваша защита типа работает.

Другие возможности для различных случаев использования:

  • , если вы уже проверяли undefined и null, но компилятор не может это выяснить, самое простое изменение - использовать оператор ненулевого подтверждения ! :

    obj[k] = typeof _e[k] === "undefined" ? "" : _e[k]!.toString(); // non-null assertion
    
  • Вы можете преобразовать свой код исключения типа в его собственное автономное выражение, чтобы вам никогда не приходилось повторно проверять исходное значение. Например:

    obj[k] = (_e[k] || "").toString(); // refactor
    

    Этот конкретный код работает только с единственными ложными значениями _e[k], которые могут иметь undefined и "". Если _e[k] может быть 0, то это даст другой результат. В общем, вы можете создать новую функцию, которая будет делать все, что вы хотите:

    function defined<T, U>(x: T | undefined, dflt: U): T | U {
        return typeof x !== "undefined" ? x : dflt;
    }
    obj[k] = defined(_e[k], "").toString(); // refactor 2
    

Хорошо, надеюсь, одна из этих подсказок; удачи!

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

0 голосов
/ 30 апреля 2020

Итак, (довольно хакерский) обходной путь, который подходит для моего варианта использования (но не во многих других сценариях ios), заключается в следующем:

obj[k] = _e[k] === undefined ? "" : String(_e[k]);

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

...