Typescript目前(或计划)是否支持安全导航操作符?。

ie:

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

此外,这个操作符是否有更常见的名称(很难为谷歌)。


当前回答

这是在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未定义,结果也未定义如果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'));

其他回答

现在可以了,请看用户“甜甜圈”的回答。

旧的回答: 关于布尔运算符的标准JavaScript行为可能会有所帮助。布尔方法在比较对象时不返回true或false,但在or情况下,第一个值等于true。

虽然不如单身好,但还是管用的:

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

你可以随心所欲地使用&&:

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

也可以使用默认值:

var name = person && person.name || "Unknown user";

还没有(截至2019年9月),但由于“安全导航操作符”现在处于第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问题——475422578)

你现在可以安装一个插件来支持它:

npm install --save-dev ts-optchain

在tsconfig.json中:

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

我希望这个答案在未来6个月左右就会过时,但希望它能同时帮助到一些人。

更新:是的,现在支持了!

它刚刚与TypeScript 3.7一起发布:https://devblogs.microsoft.com/typescript/announcing-typescript-3-7/

它被称为可选链接:https://devblogs.microsoft.com/typescript/announcing-typescript-3-7/#optional-chaining

有以下内容:

let x = foo?.bar.baz(); 

等价于:

let x = (foo === null || foo === undefined) ?
    undefined :
    foo.bar.baz();

旧的答案

在github上有一个开放的功能请求,你可以在那里发表你的意见/愿望:https://github.com/Microsoft/TypeScript/issues/16

这是在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未定义,结果也未定义如果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'));

终于来了!

下面是一些例子:

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

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

我只是没有一个解释,为什么他们不编译为foo == null