非空断言操作符(!)
具体是指在上下文中当类型检查器无法断定类型时,一个新的后缀表达式操作符 ! 可以用于断言操作对象是非 null 和非 undefined 类型。具体而言,x! 将从 x 值域中排除 null 和 undefined 。
1. 赋值时忽略 undefined 和 null
function myFn(value: string | undefined | null) {
const onlyString: string = value; // Error
const onlyString1: string = value!; // Ok
}
2. 函数调用时忽略 undefined 和 null
type MyGenerator = () => number
function myFn(myGenerator: MyGenerator | undefined | null) {
const num1 = myGenerator();//Error, 不能调用可能是 "null" 或“未定义”的对象
const num2 = myGenerator!();//ok
}
可选链操作符(?.)
可选链操作符( ?. )允许读取位于连接对象链深处的属性的值,而不必明确验证链中的每个引用是否有效。?. 操作符的功能类似于 . 链式操作符,不同之处在于,在引用为空(nullish ) (null 或者 undefined) 的情况下不会引起错误,该表达式短路返回值是 undefined。与函数调用一起使用时,如果给定的函数不存在,则返回 undefined。
就是代码运行时如果遇到 null 或 undefined 就可以⽴即停⽌某些表达式的运⾏,直接返回undefined
语法和练习:
obj?.prop
obj?.[expr]
arr?.[index]
func?.(args
const obj = {
foo: {
bar: {
baz: 42,
},
},
};
const baz = obj?.foo?.bar?.baz; // 42
const safe = obj?.qux?.baz; // undefined
console.log('baz', baz, safe)
可选元素访问:
可选链除了支持可选属性的访问之外,它还支持可选元素的访问,它的行为类似于可选属性的访问,只是可选元素的访问允许我们访问非标识符的属性,比如任意字符串、数字索引和 Symbol
- 会自动检测输入参数 arr 的值是否为 null 或 undefined,从而保证了我们代码的健壮性
const getArrIndex = <T>(arr: T[], index: number) => {
return arr?.[index]
}
//编译后的ES5语法
"use strict";
function getArrIndex(arr, index) {
if (index === void 0) { index = 0; }
return arr === null || arr === void 0 ? void 0 : arr[index];
}
可选链与函数调用:
当尝试调用一个可能不存在的方法时也可以使用可选链,系统中某个方法不可用,有可能是由于版本不一致或者用户设备兼容性问题导致的。函数调用时如果被调用的方法不存在,使用可选链可以使表达式自动返回 undefined 而不是抛出一个异常。
const result = obj.customMethod?.();
注意:
- 如果存在一个属性名且该属性名对应的值不是函数类型,使用 ?. 仍然会产生一个 TypeError 异常。
- 可选链的运算行为被局限在属性的访问、调用以及元素的访问 —— 它不会沿伸到后续的表达式中,也就是说可选调用不会阻止 a?.b / someMethod() 表达式中的除法运算或 someMethod 的方法调用。
空值合并运算符(??)
当左侧操作数为 null 或 undefined 时,其返回右侧的操作数,否则返回左侧的操作数。
const rr= null ?? 'nordon'; // 返回nodedon
const dd = 0 ?? 18; // 返回 0
const cc = 0 || 18; // 返回 18
短路:
当空值合并运算符的左表达式不为 null 或 undefined 时,不会对右表达式进行求值。
function A() { console.log('A was called'); return undefined;}
function B() { console.log('B was called'); return false;}
function C() { console.log('C was called'); return "foo";}
console.log(A() ?? C());
//A was called
//C was called
//foo
console.log(B() ?? C());
//B was called
//false
不能与 && 或 || 操作符共用
若空值合并运算符 ?? 直接与 AND(&&)和 OR(||)操作符组合使用 ?? 是不行的。这种情况下会抛出 SyntaxError。当使用括号来显式表明优先级时是可行的
null || undefined ?? "foo"; // raises a SyntaxError 不能在不使用括号的情况下混用 "||" 和 "??" 操作。
true && undefined ?? "foo"; // raises a SyntaxError 不能在不使用括号的情况下混用 "&&" 和 "??" 操作
(true && undefined) ?? "foo"; //ok
与可选链操作符 ?. 的关系
空值合并运算符针对 undefined 与 null 这两个值,可选链式操作符 ?. 也是如此。可选链式操作符,对于访问属性可能为 undefined 与 null 的对象时非常有用
interface A {
name: string;
city?: string;
}
let customer: A = {
name: "mary"
};
let customerCity = customer?.city ?? "Unknown city";
console.log(customerCity); // 输出:Unknown city
可选属性(?:)
接⼝是⼀个很重要的概念,它是对⾏为的抽象,⽽具体如何⾏动需要由类去实现。TypeScript 中的接⼝是⼀个⾮常灵活的概念,除了可⽤于对类的⼀部分⾏为进⾏抽象以外,也常⽤于对「对象的形状(Shape)」进⾏描述。
interface Person {
name: string;
age: number;
}
//类型 "{ name: string; }" 中缺少属性 "age",但类型 "Person" 中需要该属性
let mary: Person = {
name: "mary" //error
};
interface Person1 {
name: string;
age?: number;
}
let mary1: Person1 = {
name: "mary" //ok
};
运算符(&)
在 TypeScript 中交叉类型是将多个类型合并为⼀个类型。通过 & 运算符可以将现有的多种类型叠加到⼀起成为⼀种类型,它包含了所需的所有类型的特性
type PartialPointX = { x: number; };
type Point = PartialPointX & { y: number; };
let point: Point = {
x: 1,
y: 1
}
运算符(|)
在 TypeScript 中联合类型(Union Types)表示取值可以为多种类型中的⼀种,联合类型使⽤ | 分隔每个类型。联合类型通常与 null 或 undefined ⼀起使⽤
const fn = (info: strong | null | undefined) => {}
数字分隔符(_)
对于⼀个数字字⾯量,现在可以通过把⼀个下划线作为它们之间的分隔符来分组数字
const num1 = 1_234_567;
// 等价
const num1 = 1234567;