-
Notifications
You must be signed in to change notification settings - Fork 3.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
第217题:TypeScript 中 ?.、??、!.、_、** 等符号的含义? #529
Comments
第一,没有 |
盘点 TypeScript 中我们常用的那些神奇符号?. 可选链(Optional Chaining)ES11(ES2020)新增的特性,TypeScript 3.7 支持了这个特性
可选链可让我们在查询具有多层级的对象时,不再需要进行冗余的各种前置校验: var info = user && user.info 又或是这种 var age = user && user.info && user.info.getAge && user.info.getAge() 很容易命中 用了 Optional Chaining ,上面代码会变成 var info = user?.info
var age = user?.info?.getAge?.() TypeScript 在尝试访问 即可选链是一种先检查属性是否存在,再尝试访问该属性的运算符 ( 目前,可选链支持以下语法操作: obj?.prop
obj?.[expr]
arr?.[index]
func?.(args) ?? 空值合并运算符(Nullish coalescing Operator)ES12(ES2021)新增的特性,TypeScript 3.7 支持了这个特性,当左侧的操作数为 // {
// "level": null
// }
var level1 = user.level ?? '暂无等级' // level1 -> '暂无等级'
var level2 = user.other_level ?? '暂无等级' // level1 -> '暂无等级' 与逻辑或操作符( // {
// "level": 0
// }
var level1 = user.level || '暂无等级' // level1 -> 暂无等级
var level2 = user.level ?? '暂无等级' // level2 -> 0 ?: 可选参数和属性TypeScript 特有的,在 TypeScript 2.0 支持了这个特性,可选参数和属性会自动把 // 使用--strictNullChecks参数进行编译
type T1 = (x?: number) => string // x的类型是 number | undefined
type T2 = (x?: number | undefined) => string // x的类型是 number | undefined 在TypeScript里,我们使用 interface Point {
x: number;
y: number;
}
let point: Point
point = {
x: 1,
y: 2
} 其中 point = {
x: 1
}
// Property 'y' is missing in type '{ x: number; }' but required in type 'Point'. 但接口里的属性不全都是必需的。 有些是只在某些条件下存在,或者根本不存在。 所以,这里就需要可选属性( interface Point {
x: number;
y: number;
z?: number; // 可选属性
}
let point: Point
point = {
x: 1,
y: 2
} 在 TypeScript 有两个内置的工具泛型可以帮助我们处理接口的可选操作:
Partial
/**
* Make all properties in T optional
*/
type Partial<T> = {
[P in keyof T]?: T[P];
} 例如: interface Point {
x: number;
y: number;
}
type PartialPoint = Partial<Point>
// PartialPoint 相当于:
// type PartialPoint = {
// x?: number;
// y?: number;
// }
// 所有属性均可选 它具体是如何实现的喃? 首先了解 interface Point {
x: number;
y: number;
}
type PointKeys = keyof Point // "x" | "y"
所以: // Partial 语法
// type Partial<T> = {
// [P in keyof T]?: T[P];
// };
interface Point {
x: number;
y: number;
}
type PartialPoint = Partial<Point>
// 第一步↓
type PartialPoint = {
[P in 'x' | 'y']?: Point[P];
}
// 第二步↓
type PartialPoint = {
x?: Point["x"];
y?: Point["y"];
}
// 最终↓
type PartialPoint = {
x?: number;
y?: number;
} 因此,实现了 Required
type Required<T> = {
[P in keyof T]-?: T[P];
} 例如: interface Point {
x?: number;
y?: number;
}
type RequiredPoint = Required<Point>
// RequiredPoint 相当于:
// type RequiredPoint = {
// x: number;
// y: number;
// }
// 所有属性均必须 ! 非空断言操作符TypeScript 特有的,在 TypeScript 2.0 支持了这个特性,在上下文中当类型检查器无法断定类型时,一个新的后缀表达式操作符 function sayHello(hello: string | undefined) {
const hi1 = hello!.toLowerCase() // OK
const hi2 = hello.toLowerCase() // Error: Object is possibly 'undefined'
} 仅仅只是骗过了编译器,当你调用 let root: (HTMLElement | null) = document.getElementById('root')
// 非空断言操作符--> 这样写只是为了骗过编译器,防止编译的时候报错,但打包后的代码可能还是会报错
root!.style.color = 'red' 非空断言操作符 与 类型守卫类型守卫用于确保该类型在一定的范围内,常用 function sayHello(hello: string | undefined) {
if(typeof hello === 'string') {
const hi = hello.toLowerCase()
}
} 但如果你这样写: function sayHello(hello: string | undefined) {
const isSay = typeof hello === 'string'
if(isSay) {
const hi1 = hello.toLowerCase() // Error: Object is possibly 'undefined'.
const hi2 = hello!.toLowerCase() // OK
}
} 就会报错,即使 但 TypeScript 4.4 RC 会修复这个问题,如果你遇到这个问题,可升级到 TypeScript 4.4 版本后 _ 数字分隔符(Numeric separators)ES12(ES2021)新增的特性,TypeScript 2.7 就已经支持了这个特性, 这个特性允许用户在数字之间使用下划线 const million = 1_000_000
const phone = 173_1777_7777
const bytes = 0xFF_0A_B3_F2
const word = 0b1100_0011_1101_0001 需要注意的是以下函数是不支持分隔符:
const million = '1_234_567'
Number(million)
// NaN
parseInt(million)
// 1
parseFloat(million)
// 1 ** 指数操作符ES7(ES2016)新增的特性 2**5 // 32 & 交叉类型(Intersection Types)在 TypeScript 中,交叉类型是将多个类型合并为一个类型,我们可以通过 type PointX = {
x: number;
}
type Point = PointX & {
y: number;
}
let point: Point = {
x: 1,
y: 2
} 如果多个类型中存在相同的属性喃? type PointX = {
x: number;
z: string;
}
type Point = PointX & {
y: number;
z: number;
}
let point: Point = {
x: 1,
y: 2,
z: 3, // Type 'number' is not assignable to type 'never'.
} 这里 type PointX = {
x: number;
z: {x: string};
}
type Point = PointX & {
y: number;
z: {z: number};
}
let point: Point = {
x: 1,
y: 2,
z: {
x: '1',
z: 2
},
} 而这样是可以的,所以,即多个类型合并为一个交叉类型时,如果多个类型间存在同名基础类型属性时,合并后的同名基础类型属性为 | 联合类型(Union Types)联合类型表示一个值可以是几种类型之一,用竖线( let user: string | number | boolean = 'an' 联合类型通常与 const helloName = (name: string | undefined) => {
/* ... */
}; 你也可以这么用: type Hello = 'say' | 'kiss' | 'smile'; |
?. 可选链 对于 不存在的 object 方便书写操作属性 obj?.print(); // obj: {}|undefined|null function prinit(s:string|undefined){
s!.slice(0); // s : string // 最好用 类型守卫 缩窄 类型,! 只会骗过编译器,实际运行代码还可能出错
} _ es2021 新增的数字分隔符,在写一些大数的时候方便书写和阅读 1_2_3_4_5===12345 ** 指数操作符 2**5 // 32 |
可是 真的没人管 '-'么?文档上老是找不到,比如 -readonly 删除只读 |
antd 源码中发现了 !. 运算符! |
No description provided.
The text was updated successfully, but these errors were encountered: