Typescript是否支持?。操作人员(还有,它叫什么名字?)

Typescript是否支持?。操作人员(还有,它叫什么名字?),typescript,Typescript,Typescript当前(或计划)是否支持的操作员?。 即: 另外,这个操作符还有一个更通用的名字吗(很难用谷歌搜索)。更新:从TypeScript 3.7开始支持它,称为可选链接: 我在报纸上找不到任何关于它的参考资料 至于如何在CoffeeScript中调用此运算符,它被称为存在运算符(特别是存在运算符的“访问器变体”) 发件人: 存在运算符?.的访问器变量可用于吸收属性链中的空引用。如果基值可能为null或未定义,请使用它,而不是点存取器 因此,存在运算符的存取器变体似乎是引用此运算符的正

Typescript当前(或计划)是否支持
的操作员?。

即:


另外,这个操作符还有一个更通用的名字吗(很难用谷歌搜索)。

更新:从TypeScript 3.7开始支持它,称为可选链接:

我在报纸上找不到任何关于它的参考资料

至于如何在CoffeeScript中调用此运算符,它被称为存在运算符(特别是存在运算符的“访问器变体”)

发件人:


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


因此,存在运算符的存取器变体
似乎是引用此运算符的正确方式;TypeScript目前似乎不支持它(尽管)。

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

const result = a?.b?.c;
这一点的长与短是TypeScript团队正在等待ECMAScript规范收紧,因此他们的实现在未来不会中断。如果他们现在实现了一些东西,那么如果ECMAScript重新定义他们的规范,那么最终需要进行重大更改

在某些东西永远不会成为标准JavaScript的地方,TypeScript团队可以按照他们认为合适的方式实现,但是对于将来添加的ECMAScript,他们希望保留语义,即使他们允许早期访问,就像他们对许多其他特性所做的那样

捷径 所以所有JavaScripts funky操作符都是可用的,包括类型转换,例如

var n: number = +myString; // convert to number
var b: bool = !!myString; // convert to bool
手动解决方案 但回到问题上来。我举了一个迟钝的例子,说明如何用JavaScript(因此也包括TypeScript)做类似的事情,尽管我绝对不认为这是一个优雅的特性,因为你真正想要的是这个特性

(foo||{}).bar;
因此,如果
foo
undefined
,则结果是
undefined
,如果
foo
已定义且具有名为
bar
且具有值的属性,则结果就是该值

我放了一张纸

对于较长的示例,这看起来相当粗略

var postCode = ((person||{}).address||{}).postcode;
链函数 如果在规范还没有确定的时候,您迫切需要一个较短的版本,我会在某些情况下使用这种方法。如果链不能满足要求或最终为空/未定义,它将计算表达式并返回默认值(请注意,
!=
在这里很重要,我们不想使用
!=
,因为我们希望这里有一点积极的变化)

功能链(exp:()=>T,d:T){
试一试{
设val=exp();
如果(val!=null){
返回val;
}
}捕获{}
返回d;
}
设obj1:{a?:{b?:string}}={
a:{
b:‘c’
}
};
//“c”
console.log(链(()=>obj1.a.b,'Nothing');
obj1={
a:{}
};
//“没什么”
console.log(链(()=>obj1.a.b,'Nothing');
obj1={};
//“没什么”
console.log(链(()=>obj1.a.b,'Nothing');
obj1=null;
//“没什么”
console.log(链(()=>obj1.a.b,'Nothing');

没有单人房那么好,但它可以工作:

var thing = foo && foo.bar || null;
您可以使用任意数量的&&A:

var thing = foo && foo.bar && foo.bar.check && foo.bar.check.x || null;
更新:是的,现在支持它! 它刚刚与TypeScript 3.7一起发布:

这称为可选链接:

随信附上以下内容:

let x = foo?.bar.baz(); 
相当于:

let x = (foo === null || foo === undefined) ?
    undefined :
    foo.bar.baz();
旧答案 github上有一个开放的功能请求,您可以在其中表达您的意见/愿望:

编辑2019年11月13日!
截至2019年11月5日,TypeScript 3.7已经发布,它现在支持
?。
可选的链接操作符操作符
?。
在TypeScript2.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(o(test).prop1).prop2, "none")

它与Visual Studio中的IntelliSense配合得非常好。

我们在使用该方法时创建了此util方法,它可以让您使用Typescript对深层属性进行类型安全访问:

/**
*对象深层属性的类型安全访问
*
*@param obj对象获取深度属性
*@param unsafeDataOperation返回deep属性的函数
*@param valueIfFail在没有此类属性的情况下返回的值
*/
导出函数getInSafe(obj:O,unsafeDataOperation:(x:O)=>T,valueifail?:any):T{
试一试{
返回未安全数据操作(obj)
}捕获(错误){
返回值fail;
}
}
//用法示例:
getInSafe(sellTicket,x=>x.phoneDetails.imeiNumber',);
//上面的例子

getInSafe(foo,x=>x.bar.check,null)如前所述,目前仍在考虑中,但到目前为止已经有几年了

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


你也可以用另一种方法,比如Lodash。它很简洁,但编译器无法判断所用属性的有效性:

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

我通常不推荐这种方法(注意性能问题),但您可以使用spread操作符浅克隆对象,然后可以访问对象上的属性

 const person = { personId: 123, firstName: 'Simon' };
 const firstName = { ...person }.firstName;
这是因为“firstName”的类型是通过“传播”的

当我有一个可以返回null的
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;
typescript推断类型的方式可能存在一些边缘情况,这将无法编译,但这通常会起作用

\uj.get(obj,'address.street.name')
非常适合没有类型的JavaScript。但对于打字脚本,我们需要
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'
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)
console.log(_.get(obj1, 'a.b.c'));
 const person = { personId: 123, firstName: 'Simon' };
 const firstName = { ...person }.firstName;
 // 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;
npm install --save-dev ts-optchain
// tsconfig.json
{
    "compilerOptions": {
        "plugins": [
            { "transform": "ts-optchain/transform" },
        ]
    },
}
// 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