TS Optional Chaining

这篇文章的由来呢,是当时在写一个 Story 的时候,因为一个 any 类型的 object ,由于无法直观地得出它是否是 undefined ,所以报了很多次错。于是,开启万能的 google,搜了一把,然后就得到了一个词:Optional Chaining.

于是乎,有了这篇文章。

Of course,这篇文章并不是我最初的第一版,也是我经过一番修缮才放出来的。同时,这篇文章中的内容,是我结合 TS 的官方文档及网上的一些博客综合而来,然后加上我自己的一些理解及例程,最终完成的,如有理解错误之处,还望指出!

下面,开始关于 Optional Chaining 的正文。

Optional Chaining 的介绍

Optional Chaining ,在代码中的使用形式呢,是这样的➡️ ?.

?. 使我们可以在遇到 nullundefined 时立即停止运行某些表达式。

那么,怎么用呢?来看一个简单的例子:

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

上面这行代码是什么意思呢?即:⬇️

  • 如果 foo 定义了,即不为 nullundefined 时,则继续执行 const x = foo.bar.baz();
  • 如果 foonullundefined 时,返回 undefined,即执行 const x = undefined;

这么说我觉得已经是相当容易理解了吧!!!😊当然,如果将以上这段代码转换成比较熟悉的形式,可能会更容易理解一些!!!⬇️

const x = (foo !== null && foo !== undefined) 
    ? foo.bar.baz() 
    : undefined;

以上这段代码,我又再一次觉得,相当简单了!!!😁

Of course,如果还是有不理解的👬,那么,我😶

还有一个需要注意的点(上面忘说了😂)

需要注意的是:
?. 只能检查左侧的变量或属性。

如果以下这段代码这种的形式,则依旧会出错:

const foo = { ba: "test" };

const x = foo?.bar.bar;

?. 只检查了左侧的 foo ,并没有检查右侧的 bar

😂😂😂

如果想要改成正确的形式,可以写成以下这种形式:

const x = foo?.bar?.bar;

再次 Of Course,自我感觉这种好麻烦啊,如果我有一个 object ,它的属性及属性的属性及属性的属性的属性。。。都无法确定是不是 undefined ,我岂不是要写成这种:const result = a?.b?.c?.d?.e?.f?.g;

😂😂😂

给官方跪了 Orz Orz Orz Orz …

难道不能用一个声明作用的符号来声明这一整行都需要 Check 吗?或者,直接将这个功能内置成默认的!

当然了,以上只是我个人的想法,毕竟天大地大官方最大😂而且,如果真的有人将代码写成 a?.b?.c?.d?.e?.f?.g 这种,我想说:👬,可以考虑换行了😂

这里是个分隔线,真的没什么内容





我总感觉忘了啥,但是想不起来了😂



上面的内容算是一个简单的介绍,继续往下看吧,骚年


⬇️

⬇️⬇️

⬇️⬇️⬇️

⬇️⬇️⬇️⬇️

⬇️⬇️⬇️⬇️⬇️

Optional Chaining 的好处

好处呢,其实我觉得看了上面的内容后,对 ?. 的好处应该已经知道个大概了。

不过,毕竟做了笔记的,还是列出来吧!别嫌我啰嗦😂

有一段代码,是用以前的(多久以前?我也不知道,反正就是 ?. 没出的时候) TS 语法写的,是这样的:

if (foo && foo.bar && foo.bar.baz()) {
	// ...
}

还有一段代码,是用现在的(我也不知道读者您们的阅读时间,总之就是 ?. 出来了一段时间,但是也没多久,大概 TS 3.7.4 版本的时间)语法写的,是这样的:

if (foo?.bar?.baz()) {
	// ...
}

比较完这两段代码,是不是一下就清晰明了了!

是不是恍然大悟!

是不是茅塞顿开!

是不是立地成佛!

好吧,就是变简单了!没之前那么长了!

这里。。。

我再加一个需要注意的点(临时起意😂)

毕竟,有些东西得一点点引出来,对吧?😁

那就是:

?. 不同于 &&

可能直接这样写出来有些不太直观,那就先来看一个例子:

"" && 1 // 0
""?.concat("hello") // "hello"

?. 判断的是是否为 nullundefined

&& 判断的是是否为 flase

感觉上,似乎还是有些莫名其妙哈😂,不过呢,能理解最好,不能理解也无所谓,反正这条不是很重要,基本上在写代码的过程中属于自然而然就懂的那种…

下面呢,是 ?. 的几个用法

首先,第一个是可选属性访问

可选属性访问是什么东西呢?就是说,?. 这个东西可以用来对 object 进行检查,检查什么呢?检查这个 object 是不是 nullundefined ,如果是 nullundefined ,那么就代表这个 object 的属性是不存在的;反之,如果这个object 不是 nullundefined ,那么就代表这个 object 的属性是可以取出来的。

这个就是可选。

当然了,在上面的解释中呢,有一点需要注意,不知道有没有看出来的,而且在前面的部分中,我有提到过,那就是:

?. 只检查左边的 object ,也就是说,foo?.bar 这样的形式,如果 foonullundefined ,则 foo?.barfoo 这里就直接返回了,根本不会走到 .bar 这一步;而如果 foo 不为 nullundefined ,则可以取 foo.bar

当然了,还有一个需要注意的小点,如果 foo 不为空,但它没有 bar 这个属性,那么 foo.bar 取出来的值为 undefined

好,言归正传,让我们来看一个例子,实际来看一下可选属性访问 的效果:

// 第一种情况,person 存在
const printCity  = (person?: any) => {
    console.log(person?.name);
};

const person = {
    name: "Jack"
};
printCity(person);

// 执行 ts-node optionalPropertyAccesses.ts
Jack

// 第二种情况,person 不存在
const printCity  = (person?: any) => {
    console.log(person?.name);
};

printCity();

// 执行 ts-node optionalPropertyAccesses.ts
undefined

以上两种情况呢,就是 ?. 的效果了。

当然,让大家看一下如果没有使用 ?. 的情况:

// object 不存在,也没有使用 ‘?.’ ,直接报错

const printCity  = (person?: any) => {
    console.log(person.name);
};

printCity();

// 执行 ts-node optionalPropertyAccesses.ts

/Users/xxx/xxx/optionalChaining/optionalPropertyAccesses.ts:2
    console.log(person.name);
                       ^
TypeError: Cannot read property 'name' of undefined
    at printCity (/Users/xxx/xxx/optionalChaining/optionalPropertyAccesses.ts:2:24)
    at Object.<anonymous> (/Users/xxx/xxx/optionalChaining/optionalPropertyAccesses.ts:9:1)
    at Module._compile (internal/modules/cjs/loader.js:778:30)
    at Module.m._compile (/Users/xxx/xxx/node_modules/ts-node/src/index.ts:536:23)
    at Module._extensions..js (internal/modules/cjs/loader.js:789:10)
    at Object.require.extensions.(anonymous function) [as .ts] (/Users/xxx/xxx/node_modules/ts-node/src/index.ts:539:12)
    at Module.load (internal/modules/cjs/loader.js:653:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:593:12)
    at Function.Module._load (internal/modules/cjs/loader.js:585:3)
    at Function.Module.runMain (internal/modules/cjs/loader.js:831:12)

当然,下面我也把上面提到的小注意点列出来,看一下:

// object 存在,属性不存在,直接为 undefined

const printCity  = (person?: any) => {
    console.log(person.city);
};

const person = {
    name: "Jack"
};
printCity(person);

// 执行 ts-node optionalPropertyAccesses.ts
undefined

下面是第二个用法:可选元素访问

可选元素访问又是什么意思呢?

就是可以用来从数组中取元素,即 ?. 可以用来检查数组是否存在

话不多说,直接上示例代码吧:

// 第一种情况,数组存在

const printFourthElement = (array?: string[]) => {
    console.log(array?.[3]);
};

const array1 = ["Jack", "Tom", "Bob", "Jeny"];
printFourthElement(array1);

// 执行 ts-node optionalElement.ts
Jeny

// 第二种情况,数组不存在

const printFourthElement = (array?: string[]) => {
    console.log(array?.[3]);
};

printFourthElement();

// 执行 ts-node optionalElement.ts
undefined

还是一样,如果没有使用 ?. ,则会报错:

// 数组不存在,没有使用 ‘?.’ ,直接报错

const printFourthElement = (array?: string[]) => {
    console.log(array[3]);
};

printFourthElement();

// 执行 ts-node optionalElement.ts

/Users/xxx/xxx/optionalChaining/optionalElement.ts:2
    console.log(array[3]);
                     ^
TypeError: Cannot read property '3' of undefined
    at printFourthElement (/Users/xxx/xxx/optionalChaining/optionalElement.ts:2:22)
    at Object.<anonymous> (/Users/xxx/xxx/optionalChaining/optionalElement.ts:7:1)
    at Module._compile (internal/modules/cjs/loader.js:778:30)
    at Module.m._compile (/Users/xxx/xxx/node_modules/ts-node/src/index.ts:536:23)
    at Module._extensions..js (internal/modules/cjs/loader.js:789:10)
    at Object.require.extensions.(anonymous function) [as .ts] (/Users/xxx/xxx/node_modules/ts-node/src/index.ts:539:12)
    at Module.load (internal/modules/cjs/loader.js:653:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:593:12)
    at Function.Module._load (internal/modules/cjs/loader.js:585:3)
    at Function.Module.runMain (internal/modules/cjs/loader.js:831:12)

再接着,是第三种用法:可选调用

我相信,看了好多个🌰了,大家已经能猜出来可选调用是什么意思了。

没错,就是方法的调用。

上吧,皮卡丘!

// 第一种情况,该方法(箭头函数...等)定义了

const printMessage = (convert?: (message: string) => string) => {
    console.log(convert?.("hello world"));
};
const convert = (message: string): string => message.toUpperCase();

printMessage(convert);

// 执行 ts-node optionalCall.ts
HELLO WORLD

// 第二种情况,该方法(箭头函数...等)没有定义

const printMessage = (convert?: (message: string) => string) => {
    console.log(convert?.("hello world"));
};

printMessage();

// 执行 ts-node optionalCall.ts
undefined

// 没有使用 '?.' 的情况,直接报错

const printMessage = (convert?: (message: string) => string) => {
    console.log(convert("hello world"));
};

printMessage();

// 执行 ts-node optionalCall.ts

/Users/xxx/xxx/optionalChaining/optionalCall.ts:2
    console.log(convert("hello world"));
                ^
TypeError: convert is not a function
    at printMessage (/Users/xxx/xxx/optionalChaining/optionalCall.ts:2:17)
    at Object.<anonymous> (/Users/xxx/xxx/optionalChaining/optionalCall.ts:7:1)
    at Module._compile (internal/modules/cjs/loader.js:778:30)
    at Module.m._compile (/Users/xxx/xxx/node_modules/ts-node/src/index.ts:536:23)
    at Module._extensions..js (internal/modules/cjs/loader.js:789:10)
    at Object.require.extensions.(anonymous function) [as .ts] (/Users/xxx/xxx/node_modules/ts-node/src/index.ts:539:12)
    at Module.load (internal/modules/cjs/loader.js:653:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:593:12)
    at Function.Module._load (internal/modules/cjs/loader.js:585:3)
    at Function.Module.runMain (internal/modules/cjs/loader.js:831:12)

下面这个呢,其实不算是用法,顶多算一个注意点

好吧,再加一个注意点:Optional Chaining 不会中断其他表达式

什么意思呢?就是说 ?. 值作用于可选属性访问、可选元素访问、可选调用。

如果 ?. 使用在某一个表达式内,那这个表达式肯定是会被检查的;

但另一个没有使用 ?. 的表达式,是不会受这个表达式中 ?. 的影响的。

话不多说,来看代码:

const printFourthElement = (array?: string[]) => {
    console.log(array?.[3].concat(", how are you?"));
    console.log(array?.[3] + ", how are you?");
};

const array1 = ["Jack", "Tom", "Bob", "Jeny"];

printFourthElement(array1);
printFourthElement();

// 执行结果----------------------

Jeny, how are you?
Jeny, how are you?
undefined
undefined, how are you?     // 重点看这个

好,基本上就这么多,然后呢,这个功能是TS 3.7 版本后出来的

如果要使用这个功能,请确保版本在 3.7 以上。

有时会不起作用,那肯定是没配置好,不过,其实真的不需要配置什么,package.json 改个版本号就完了。😂

或者原版本升下级,卸了重装?随便!实在不行,IDE 关了重启?

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

十甫寸木南

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值