打字稿是否支持?运营商? (而且,它叫什么?)

时间:2013-03-07 00:11:24

标签: typescript

Typescript目前(或有计划)是否支持?.的{​​{3}}运算符

即:

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

此外,这个运营商是否有一个更常见的名称(它很难谷歌)。

16 个答案:

答案 0 :(得分:118)

不如单身好吗?但它有效:

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

你可以使用尽可能多的&&如你所愿:

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

答案 1 :(得分:80)

我在TypeScript language specification中找不到任何引用。

至于在CoffeeScript中调用此运算符的内容,它被称为存在运算符(具体地说,是存在运算符的“存取变量”)。

来自CoffeeScript's documentation on Operators

  

存在运算符?.的访问器变体可用于在属性链中吸收空引用。如果基值可能 null 未定义,请使用它代替点访问器.

因此,存在运算符的存取器变体似乎是引用此运算符的正确方法;和TypeScript目前似乎不支持它(尽管others have expressed a desire for this functionality)。

答案 2 :(得分:59)

这是在ECMAScript可选链接规范中定义的,因此在讨论时我们应该参考可选链接。可能的实施:

const result = a?.b?.c;

这一点的长短之处在于TypeScript团队正在等待ECMAScript规范收紧,因此它们的实现在未来可能不会中断。如果他们现在实现了某些东西,那么如果ECMAScript重新定义他们的规范,最终将需要进行重大改变。

请参阅Optional Chaining Specification

在某些东西永远不会成为标准JavaScript的情况下,TypeScript团队可以在他们认为合适的情况下实现,但是对于未来的ECMAScript添加,他们希望保留语义,即使它们提供早期访问,因为它们具有许多其他功能。

短切

因此所有JavaScripts时髦运算符都可用,包括类型转换,如...

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

手动解决方案

但回到这个问题。我有一个很明显的例子,说明你如何在JavaScript(以及TypeScript)中做类似的事情,虽然我绝对不会暗示它是一个优雅的,因为你真正追求的功能。

(foo||{}).bar;

因此,如果fooundefined,则结果为undefined,如果foo已定义并且具有名为bar的属性具有值,则结果为是那个价值。

我放了example on JSFiddle

对于较长的例子,这看起来很粗略。

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

链函数

如果您在规格尚未播出时急需较短的版本,我会在某些情况下使用此方法。它评估表达式并返回默认值,如果链不能满足或结束null / undefined(注意!=在这里很重要,我们想要使用{{ 1}}因为我们想要一些积极的玩杂耍。)

!==

答案 3 :(得分:30)

github上有一个开放的功能请求,您可以在其中表达您的意见/愿望:https://github.com/Microsoft/TypeScript/issues/16

答案 4 :(得分:18)

编辑:由于fracz评论,我已经更新了答案。

TypeScript 2.0发布!.它与?.(C#中的安全导航器)不同

有关详细信息,请参阅此答案:

https://stackoverflow.com/a/38875179/1057052

这只会告诉编译器该值不为null或未定义。这将检查值是null还是未定义。

TypeScript Non-null assertion operator

// 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
}

答案 5 :(得分:11)

TypeScript 3.7支持Elvis(?。)可选链接运算符。

您可以使用它来检查null值:如果cats为null或未定义,cats?.miows返回null。

您也可以将其用于可选的方法调用:cats.doMiow?.(5)将调用doMiow(如果存在)。

还可以访问属性:cats?.['miows']

参考:https://devblogs.microsoft.com/typescript/announcing-typescript-3-7-beta/

答案 6 :(得分: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")

它在Visual Studio中与IntelliSense配合得很好。

答案 7 :(得分:2)

这称为可选链接,位于Typescript 3.7

  

可选链接使我们可以编写代码,以便立即停止   如果遇到null或未定义,则运行一些表达式

答案 8 :(得分:1)

我们在使用Phonetradr时创建了这个util方法,它可以使用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);

答案 9 :(得分:1)

我通常不推荐这种方法(注意性能问题),但是您可以使用spread运算符来浅克隆对象,然后可以访问该对象。

class UserDetails(viewsets.ModelViewSet):
    def get_queryset(self):
        user_id = self.request.query_params.get('user_id')
        if user_id:
           return UserModel.objects.filter(id=user_id).first()
        return UserModel.objects.none()

之所以可行,是因为“名字”的类型是“传播”到的。

当我有一个 const person = { personId: 123, firstName: 'Simon' }; const firstName = { ...person }.firstName; 表达式可以返回null并且需要一个单独的属性时,我会经常使用它:

find(...)

打字稿可能会在某些情况下推断类型,因此无法编译,但这通常可以正常工作。

答案 10 :(得分:1)

终于来了!

以下是一些示例:

// properties
foo?.bar
foo?.bar()
foo?.bar.baz()
foo?.bar?.baz()

// indexing
foo?.[0]
foo?.['bar']

// check if a function is defined before invoking
foo?.()
foo.bar?.()
foo?.bar?.()

但这与您的假设并不完全相同。

而不是评估

foo?.bar

对于这个小代码段,我们都习惯于编写

foo ? foo.bar : null

它实际评估为

(foo === null || foo === undefined) ?
    undefined :
    foo.bar

适用于所有falsey值,例如空字符串,0或false。

对于他们为什么不将其编译为foo == null

,我只是没有解释。

答案 11 :(得分:0)

如前所述,它目前仍在考虑中,但到目前为止已经考虑了has been dead in the water

在现有答案的基础上,这是我能想到的最简洁的手册版本:

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'));

答案 12 :(得分:0)

_.get(obj, 'address.street.name')非常适合没有类型的JavaScript。但是对于TypeScript,我们需要真正的Elvis运算符!

答案 13 :(得分:0)

尚未(截至2019年9月),但是自“安全导航操作员” is now at Stage 3起,它已在TypeScript中实现。

观看此问题以获取更新:

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

几个引擎有较早的实现:

JSC: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个月左右会过时,但希望它能在此期间对某人有所帮助。

答案 14 :(得分:0)

我想这就是你要找的。 Powerbite

处的类似示例
/**
 * 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);

答案 15 :(得分:-8)

在2.9版中支持! https://github.com/Microsoft/TypeScript/wiki/What%27s-new-in-TypeScript#non-null-assertion-operator

const a = {}
console.log(a!.b!.c)

.tsconfig中不需要任何其他选项