2024.7.1 更
- 一个对象中必须存在 a 或者 b 属性,但是又不能同时存在
type AOrB = { a: string; b?: never } | { b: string; a?: never }
2024.2.18 更
- 重载: 方法同名,但是参数和返回值类型不一样
// 当传递了 key,返回对应 key 的值,没有传递 key,则返回整个对象
useGray(): Record<string, boolean>
useGray(key: string): boolean
useGray(key?: string): boolean | Record<string, boolean> {
// 具体实现
}
上面这个需求用泛型就无法实现了,很多三方库也有类似的用法。
2024.2.8 更
- 字符串转数字
type StringToNumber<S extends string> = S extends `${infer N extends number}` ? N : number
- tsconfig配置项详解
其是对整个
tsconfig
所在文件夹及子目录生效
{
"compilerOptions": {
"module": "commonjs", // 用来指定要使用的模块化的规范,默认 commonjs
"target": "es2017", // 需要兼容到的版本(取决于你想运行在什么浏览器上面),默认 es3
"lib": ["ESNext"], // 指定要包含在编译中的库文件,默认 []
"path": {
"app/*": ["./src/app/*"]
} // 将导入重新映射到其他查找位置
// 其他规则...
},
"exclude": ["node_modules", "dist"], // 排除特定文件
"extends": "./tsconfig.base.json",
}
- 可以使用
global.d.ts
在全局定义,也可以覆盖三方库中的定义 可以使用下面这种方式来声明,也可以使用export
、import
/// <reference path="./types/xxx.d.ts" />
declare module 'xxx' {
export type Module = {
name: string
}
}
类型关系
类型之间的并集(|
)会向上取顶部的类型。
即 never | 'a' => 'a'
,unknown | 'a' => 'unknown'
类型之间的交集(&
)会向下取底部的类型。
即 never & 'a' = never
,unknown & 'a' => 'a'
bottom Type: never
,top Type: unknown
,既是 top Type
也是 bottom Type
: any
类型
- 联合类型
type Union = Name | Age
- 交叉类型
type Intersection = Name & Age
- 元组类型(TS 中的元组使用数组来表示)
type Turple = [Name, Age]
关键字
keyof
: 将对象中所有的键取出来组成联合类型,如果这个类型是基本类型的话,就是将基本类型中的方法取出来组成联合类型
// 'name' | 'age'
type Keys = keyof Union
// "toFixed" | "toExponential" | "toPrecision" | "toString" | "toLocaleString" | "valueOf"
type NumberKeys = keyof number
extends
: 判断左右的类型是不是小于等于右边的类型
type Extends<A, B> = A extends B ? true : false
infer
: 推断真正的类型
type First<T> = T extends [infer A] ? A : any
in
: 遍历所有的key
type In = { [P in keyof Name]: Name[P] }
as
: 转换对应的key
- `: 字符串
type As = { [P in keyof Name as `get${P}`]: Name[P] }
7: is
: 缩小类型
declare function isString(val: unknown) val is string
thisType
: 推断方法中的this
拥有哪些方法和属性 必须在tsconfig.json
中配置"noImplicitThis": true
type GetComputed<C> = C extends Record<string, (...args: any[]) => any>
? { [S in keyof C]: ReturnType<C[S]> }
: never
declare function SimpleVue<D, C, M>(
options: {
data: (this: void) => D
computed: C & ThisType<D>
methods: M
} & ThisType<D & M & GetComputed<C>>
): unknown
注意点:联合类型不需要使用 in
也是会触发其分发特性的
type MyExclude<T, U extends T> = T extends U ? never : T
逆变 / 协变
参数和返回值都应该比当前设置的类型更小。
常见技巧
获取数组长度
type Length<T extends unknown[]> = T['length']
联合两个数组
type Concat<A extends unknown[], B extends unknown[]> = [...A, ...B]
获取函数的返回值
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;
元组、联合、交叉类型的互相转换
这个里面使用到了协变和逆变。
// 1. 元组转联合类型
type TurpleToUnion<T extends unknown[]> = T[number]
// 2. 联合类型转交叉类型
type UnionToIntersection<T> = (
T extends object ? (k: T) => void : never
) extends (k: infer U) => void
? U
: never
// 3. 联合类型转元组类型
type LastInUnion<U> = UnionToIntersection<
U extends unknown ? (x: U) => 0 : never
> extends (x: infer L) => 0
? L
: never
type UnionToTurple<T, L = LastInUnion<T>> = [T] extends [never]
? []
: [...UnionToTurple<Exclude<T, L>>, L]
字符串转元组
type StringToTurple<T extends string> = T extends `${infer F}${infer L}`
? [F, ...StringToTurple<L>]
: []
判断是不是 never/any
type IsNever<T> = [T] extends [never] ? true : false
type IsAny<T> = 0 extends (1 & T) ? true : false
判断两个数字的大小
type IsLess<
A extends number,
B extends number,
I extends any[] = []
> = B extends I["length"]
? true
: A extends I["length"]
? false
: IsLess<A, B, [...I, 0]>
支持特定范围内的数字
type Range<
Begin extends number,
End extends number,
I extends number[] = []
> = End extends I["length"]
? [I["length"]]
: IsLess<I["length"], Begin> extends false
? Range<Begin, End, [...I, 0]>
: [I["length"], ...Range<Begin, End, [...I, 0]>]
增加/减少修饰符
Readonly
、Partial
等
重载
function toString(x: string): string;
function toString(x: number): string;
// 实现签名(函数体具体实现)
function toString(x: string | number) {
return String(x)
}
防御性编程
interface Foo { type: 'foo' }
interface Bar { type: 'bar' }
type All = Foo | Bar
function handleValue(val: All) {
switch (val.type) {
case 'foo':
// 这里 val 被收窄为 Foo
break
case 'bar':
// val 在这里是 Bar
break
default:
// val 在这里是 never
const exhaustiveCheck: never = val
break
}
}