Поддерживает ли Typescript?. оператор? (И, что он называл?)

Использует ли Typescript (или планирует ли он) поддерживать безопасную навигацию оператора ?.

т

var thing = foo?.bar
// same as:
var thing = (foo) ? foo.bar : null;

Кроме того, существует ли более распространенное имя для этого оператора (для него не всегда сложно использовать Google).

Ответ 1

Я не могу найти никакой ссылки на него в TypeScript спецификация языка.

Что касается вызова этого оператора в CoffeeScript, он называется экзистенциальным оператором (в частности, "вариантом доступа" экзистенциального оператора).

Из Документация CoffeeScript для операторов:

Вариант доступа экзистенциального оператора ?. может использоваться для вставки нулевых ссылок в цепочке свойств. Используйте его вместо точки доступа . в тех случаях, когда базовое значение может быть null или undefined.

Таким образом, вариант варианта доступа экзистенциального оператора представляется правильным способом обращения к этому оператору; и TypeScript в настоящее время не поддерживает его (хотя другие выразили желание этой функции).

Ответ 2

Не так хорошо, как сингл?, но он работает:

var thing = foo && foo.bar || null;

Вы можете использовать как можно больше && как вам нравится:

var thing = foo && foo.bar && foo.bar.check && foo.bar.check.x || null;

Ответ 3

Это определено в спецификации факультативной цепочки ECMAScript, поэтому, вероятно, нам следует обратиться к необязательной цепочке, когда мы обсудим это. Вероятная реализация:

const result = a?.b?.c;

Суть этого в том, что команда TypeScript ждет ужесточения спецификации ECMAScript, поэтому их реализация в будущем может быть непоколебимой. Если бы они внедрили что-то сейчас, в конечном итоге потребовались бы серьезные изменения, если бы ECMAScript переопределил их спецификацию.

См. Дополнительную спецификацию цепочки

Там, где что-то никогда не будет стандартным JavaScript, команда TypeScript может реализовать по своему усмотрению, но для будущих добавлений ECMAScript они хотят сохранить семантику, даже если они предоставляют ранний доступ, как и для многих других функций.

Короткие сокращения

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

var n: number = +myString; // convert to number
var b: bool = !!myString; // convert to bool

Ручное решение

Но вернемся к вопросу. У меня есть тупой пример того, как вы можете сделать похожую вещь в JavaScript (и, следовательно, в TypeScript), хотя я определенно не предполагаю, что это изящная функция, которая вам действительно нужна.

(foo||{}).bar;

Таким образом, если foo не undefined результат не undefined и если foo определен и имеет свойство с именем bar, у которого есть значение, результатом является это значение.

Я положил пример на JSFiddle.

Это выглядит довольно схематично для более длинных примеров.

var postCode = ((person||{}).address||{}).postcode;

Функция цепи

Если вы отчаянно нуждаетесь в более короткой версии, пока спецификация находится в стадии разработки, я использую этот метод в некоторых случаях. Он вычисляет выражение и возвращает значение по умолчанию, если цепочка не может быть удовлетворена или заканчивается null/undefined (обратите внимание, что != Здесь важно, мы не хотим использовать !== как мы хотим немного положительного жонглирования здесь).

function chain<T>(exp: () => T, d: T) {
    try {
        let val = exp();
        if (val != null) {
            return val;
        }
    } catch { }
    return d;
}

let obj1: { a?: { b?: string }} = {
    a: {
        b: 'c'
    }
};

// 'c'
console.log(chain(() => obj1.a.b, 'Nothing'));

obj1 = {
    a: {}
};

// 'Nothing'
console.log(chain(() => obj1.a.b, 'Nothing'));

obj1 = {};

// 'Nothing'
console.log(chain(() => obj1.a.b, 'Nothing'));

obj1 = null;

// 'Nothing'
console.log(chain(() => obj1.a.b, 'Nothing'));

Ответ 5

Изменить: Я обновил ответ благодаря комментарию fracz.

TypeScript 2.0 выпущен !. Это не то же самое, что ?. (безопасный навигатор на С#)

См. этот ответ для получения более подробной информации:

fooobar.com/questions/63500/...

Это говорит только компилятору, что значение не равно null или undefined. Это будет не, если значение равно null или undefined.

TypeScript Оператор ненулевого утверждения

// Compiled with --strictNullChecks
function validateEntity(e?: Entity) {
    // Throw exception if e is null or invalid entity
}

function processEntity(e?: Entity) {
    validateEntity(e);
    let s = e!.name;  // Assert that e is non-null and access name
}

Ответ 6

Оператор ?. не поддерживается в TypeScript версии 2.0.

Поэтому я использую следующую функцию:

export function o<T>(someObject: T, defaultValue: T = {} as T) : T {
    if (typeof someObject === 'undefined' || someObject === null)
        return defaultValue;
    else
        return someObject;
}

использование выглядит так:

o(o(o(test).prop1).prop2

Кроме того, вы можете установить значение по умолчанию:

o(o(o(o(test).prop1).prop2, "none")

Это работает очень хорошо с IntelliSense в Visual Studio.

Ответ 7

Мы создали этот метод util при работе над Phonetradr, который может предоставить вам безопасный доступ к глубоким свойствам с помощью Typescript:

/**
 * Type-safe access of deep property of an object
 *
 * @param obj                   Object to get deep property
 * @param unsafeDataOperation   Function that returns the deep property
 * @param valueIfFail           Value to return in case if there is no such property
 */
export function getInSafe<O,T>(obj: O, unsafeDataOperation: (x: O) => T, valueIfFail?: any) : T {
    try {
        return unsafeDataOperation(obj)
    } catch (error) {
        return valueIfFail;
    }
}

//Example usage:
getInSafe(sellTicket, x => x.phoneDetails.imeiNumber, '');

//Example from above
getInSafe(foo, x => x.bar.check, null);

Ответ 8

Обычно я не рекомендую этот подход (следите за проблемами производительности), но вы можете использовать оператор распространения для поверхностного клонирования объекта, к которому затем можно получить доступ к свойству.

 const person = { personId: 123, firstName: 'Simon' };
 const firstName = { ...person }.firstName;

Это работает, потому что тип 'firstName' распространяется через.

Я буду использовать это чаще всего, когда у меня есть выражение find(...) которое может возвратить ноль, и мне нужно одно свойство из него:

 // this would cause an error (this ID doesn't exist)
 const people = [person];
 const firstName2 = people.find(p => p.personId == 999).firstName;

 // this works - but copies every property over so raises performance concerns
 const firstName3 = { ...people.find(p => p.personId == 999) }.firstName;

Могут быть некоторые крайние случаи с тем, как машинопись выводит типы, и это не скомпилируется, но в целом это должно работать.

Ответ 9

Оператор Элвиса (?) Поддерживается в TypeScript 3.7.

Вы можете использовать его для проверки на нулевые значения: cats?.miows возвращает ноль, если кошки нулевые или неопределенные.

Вы также можете использовать его для необязательного вызова метода: cats.doMiow?(5) вызовет doMiow, если он существует.

Ссылка: https://devblogs.microsoft.com/typescript/announcing-typescript-3-7-beta/

Ответ 10

Как уже было сказано ранее, в настоящее время он все еще рассматривается, но уже несколько лет находится в воде.

Основываясь на существующих ответах, вот самая краткая версия руководства, которую я могу придумать:

jsfiddle

function val<T>(valueSupplier: () => T): T {
  try { return valueSupplier(); } catch (err) { return undefined; }
}

let obj1: { a?: { b?: string }} = { a: { b: 'c' } };
console.log(val(() => obj1.a.b)); // 'c'

obj1 = { a: {} };
console.log(val(() => obj1.a.b)); // undefined
console.log(val(() => obj1.a.b) || 'Nothing'); // 'Nothing'

obj1 = {};
console.log(val(() => obj1.a.b) || 'Nothing'); // 'Nothing'

obj1 = null;
console.log(val(() => obj1.a.b) || 'Nothing'); // 'Nothing'

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


Хотя это работает для простых случаев, если вам нужны более сложные вещи, такие как вызов функции и последующий доступ к свойству результата, то все другие ошибки также проглатываются. Плохой дизайн.

В вышеприведенном случае оптимизированная версия другого ответа, размещенного здесь, является лучшим вариантом:

jsfiddle

function o<T>(obj?: T, def: T = {} as T): T {
    return obj || def;
}

let obj1: { a?: { b?: string }} = { a: { b: 'c' } };
console.log(o(o(o(obj1).a)).b); // 'c'

obj1 = { a: {} };
console.log(o(o(o(obj1).a)).b); // undefined
console.log(o(o(o(obj1).a)).b || 'Nothing'); // 'Nothing'

obj1 = {};
console.log(o(o(o(obj1).a)).b || 'Nothing'); // 'Nothing'

obj1 = null;
console.log(o(o(o(obj1).a)).b || 'Nothing'); // 'Nothing'

Более сложный пример:

o(foo(), []).map((n) => n.id)

Вы также можете пойти другим путем и использовать что-то вроде Lodash ' _.get(). Это сжато, но компилятор не сможет судить о правильности используемых свойств:

console.log(_.get(obj1, 'a.b.c'));

Ответ 11

Пока нет (по состоянию на сентябрь 2019 г.), но поскольку "оператор безопасной навигации" теперь находится на этапе 3, он реализован в TypeScript.

Следите за обновлениями:

https://github.com/microsoft/TypeScript/issues/16

Несколько движков имеют ранние реализации:

ОАО: https://bugs.webkit.org/show_bug.cgi?id=200199

V8: https://bugs.chromium.org/p/v8/issues/detail?id=9553

SM: https://bugzilla.mozilla.org/show_bug.cgi?id=1566143

(через https://github.com/tc39/proposal-optional-chaining/issues/115#issue-475422578)

Вы можете установить плагин для его поддержки сейчас:

npm install --save-dev ts-optchain

В вашем tsconfig.json:

// tsconfig.json
{
    "compilerOptions": {
        "plugins": [
            { "transform": "ts-optchain/transform" },
        ]
    },
}

Я ожидаю, что этот ответ устареет в ближайшие 6 месяцев или около того, но, надеюсь, он тем временем кому-то поможет.

Ответ 12

_.get(obj, 'address.street.name') отлично работает для JavaScript, где у вас нет типов. Но для TypeScript нам нужен настоящий оператор Элвиса!