Typescript是否支持?。运营商吗?(And, what's it called?)

Typescript目前(或有计划)支持?.安全航行操作符吗

即:

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

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

388946 次浏览

从TypeScript 3.7(发布于2019年11月5日)开始,这个特性被支持,并被称为可选的链接:

从本质上讲,可选链接让我们编写的代码中,TypeScript可以在遇到nullundefined时立即停止运行某些表达式。可选链接中的明星是针对可选的属性访问的新?.操作符。

更多细节请参考TypeScript 3.7发布说明


在3.7版本之前,TypeScript中不支持这一点,尽管早在问题#16关于TypeScript回购(可以追溯到2014年)时就有人请求过。

至于该怎么称呼这个运算符呢,似乎还没有达成共识。除了“可选连锁”;(也就是它被称为在JavaScript中斯威夫特),还有一些其他的例子:

存在操作符?.的访问器变体可用于吸收属性链中的空引用。在基本值可能是未定义的的情况下,使用它来代替点访问器.

空条件操作符对其操作数应用成员访问(?.)或元素访问(?[])操作,仅当该操作数的计算结果为非空时;否则,返回null

可能还有很多其他的例子。

这是在ECMAScript可选链接规范中定义的,所以在讨论这个问题时,我们可能应该参考可选的链接。可能实现:

const result = a?.b?.c;

从长期和短期来看,TypeScript团队正在等待ECMAScript规范的收紧,这样他们的实现就可以在未来不中断。如果他们现在实现了一些东西,如果ECMAScript重新定义了他们的规范,那么最终需要进行重大更改。

看到# EYZ0

如果有些东西永远不会成为标准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的属性,则结果为该值。

我输入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'));

现在是可能的,见用户“甜甜圈”的答案。

< p >老回答: 关于布尔运算符的标准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";

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

它刚刚与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

2019年11月13日编辑!

截至2019年11月5日,TypeScript 3.7已经发布,它现在支持 ?.可选的链接运算符🎉🎉🍾🍾🎉!!

https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#optional-chaining

<人力资源/ >

仅供历史用途:

多亏了fracz的评论,我更新了答案。

TypeScript 2.0发布的!.?.(c#中的安全导航器)不一样

更多细节请参见以下答案:

https://stackoverflow.com/a/38875179/1057052 < a href = " https://stackoverflow.com/a/38875179/1057052 " > < / >

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

TypeScript非空断言运算符 . rref ="https://github.com/Microsoft/TypeScript/wiki/What's-new-in-TypeScript#non-null-assertion-operator" rel="noreferrer

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

在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中的智能感知一起工作得非常好。

我们在开发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);

正如之前所回答的,目前它仍在考虑中,但到目前为止它已经已经死在水里了几年了。

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

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

我一般不推荐这种方法(注意性能问题),但是您可以使用扩散操作符来浅克隆一个对象,然后您可以访问该对象上的属性。

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

这是可行的,因为'firstName'类型是通过'传播'的。

我将使用这个最频繁的时候,我有一个find(...)表达式,可以返回null,我需要一个单一的属性:

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

typescript推断类型的方式可能有一些边缘情况,这不会被编译,但这通常应该是可行的。

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

还没有(截至2019年9月),但从“安全导航操作符”现在处于第三阶段开始,它就在TypeScript中实现了。

关注这个问题的更新:

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

有几个引擎有早期的实现:

JSC: # EYZ0

V8: # EYZ0

SM: # EYZ0

(通过# EYZ0)

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

npm install --save-dev ts-optchain

在tsconfig.json中:

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

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

猫王(? ?)可选的链接操作符在TypeScript 3.7中被支持。

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

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

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

参考:# EYZ0

它被称为可选链接,它在打字稿3.7

可选的链接让我们编写代码,我们可以立即停止 如果遇到null或undefined

,则运行一些表达式

终于来了!

下面是一些例子:

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

我觉得这就是你要找的东西。类似的例子在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);