typescript-builtins-extended 0.0.1 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +31 -0
- package/README.md +23 -7
- package/global.d.ts +205 -0
- package/index.d.ts +203 -26
- package/package.json +14 -2
- package/tsconfig.json +5 -4
- package/README.zh-CN.md +0 -15
- package/src/00005-extreme-readonly-keys.ts +0 -34
- package/src/00009-medium-deep-readonly.ts +0 -69
- package/src/00010-medium-tuple-to-union.ts +0 -18
- package/src/00011-easy-tuple-to-object.ts +0 -32
- package/src/00014-easy-first.ts +0 -27
- package/src/00015-medium-last.ts +0 -20
- package/src/00016-medium-pop.ts +0 -22
- package/src/00730-hard-union-to-tuple.ts +0 -52
- package/src/test-utils.ts +0 -31
package/README.en.md
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Typescript Utilities
|
|
2
|
+
|
|
3
|
+
English | [简体中文](README.md)
|
|
4
|
+
|
|
5
|
+
`typescript-builtins-extended` does not provide any js code and focuses on typescript type deduction.
|
|
6
|
+
|
|
7
|
+
## Usage
|
|
8
|
+
|
|
9
|
+
There are two ways to use it, module introduction and global introduction.
|
|
10
|
+
|
|
11
|
+
### Module introduction
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { Prettify } from 'typescript-builtins-extended'
|
|
15
|
+
|
|
16
|
+
type A = Prettify<{ a: number } & { b: string }>
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### Global introduction
|
|
20
|
+
|
|
21
|
+
Add the following code to a global declaration file, such as `global.d.ts`.
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
/// <reference types="typescript-builtins-extended/global" />
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
You can then use `typescript-builtins-extended` just like the built-in utility types.
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
type A = Prettify<{ a: number } & { b: string }>
|
|
31
|
+
```
|
package/README.md
CHANGED
|
@@ -1,15 +1,31 @@
|
|
|
1
1
|
# Typescript Utilities
|
|
2
2
|
|
|
3
|
-
English
|
|
3
|
+
[English](README.en.md) | 简体中文
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
`typescript-builtins-extended` 不提供任何 js 代码,专注于 typescript 的类型推导。
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## 使用方式
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
有两种使用方式,模块引入和全局引入。
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
### 模块引入
|
|
12
12
|
|
|
13
|
-
```
|
|
14
|
-
|
|
13
|
+
```typescript
|
|
14
|
+
import type { Prettify } from 'typescript-builtins-extended'
|
|
15
|
+
|
|
16
|
+
type A = Prettify<{ a: number } & { b: string }>
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### 全局引入
|
|
20
|
+
|
|
21
|
+
将下面的代码添加到全局声明文件中,例如 `global.d.ts`。
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
/// <reference types="typescript-builtins-extended/global" />
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
然后就可以像使用内置实用程序类型一样使用 `typescript-builtins-extended` 了。
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
type A = Prettify<{ a: number } & { b: string }>
|
|
15
31
|
```
|
package/global.d.ts
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
type Whitespace = " " | "\n" | "\t";
|
|
2
|
+
export {};
|
|
3
|
+
declare global {
|
|
4
|
+
/**
|
|
5
|
+
* 判断两个类型是否相等
|
|
6
|
+
*/
|
|
7
|
+
type Equal<X, Y> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2 ? true : false;
|
|
8
|
+
/**
|
|
9
|
+
* 判断两个类型是否不相等
|
|
10
|
+
*/
|
|
11
|
+
type NotEqual<X, Y> = true extends Equal<X, Y> ? false : true;
|
|
12
|
+
/**
|
|
13
|
+
* 判断类型是否为 any
|
|
14
|
+
*/
|
|
15
|
+
type IsAny<T> = 0 extends 1 & T ? true : false;
|
|
16
|
+
/**
|
|
17
|
+
* 判断类型是否不为 any
|
|
18
|
+
*/
|
|
19
|
+
type NotAny<T> = true extends IsAny<T> ? false : true;
|
|
20
|
+
/**
|
|
21
|
+
* 将类型 T 格式化输出,显示为单一对象类型
|
|
22
|
+
*/
|
|
23
|
+
type Prettify<T> = {
|
|
24
|
+
[K in keyof T]: T[K];
|
|
25
|
+
} & {};
|
|
26
|
+
/**
|
|
27
|
+
* Prettify 的别名,用于测试类型结果
|
|
28
|
+
*/
|
|
29
|
+
type Debug<T> = {
|
|
30
|
+
[K in keyof T]: T[K];
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* 根据条件 C 判断返回类型 T 或 F
|
|
34
|
+
*/
|
|
35
|
+
type If<C extends boolean, T, F> = C extends true ? T : F;
|
|
36
|
+
/**
|
|
37
|
+
* 从字符串中移除前面的 空格 或 指定的字符
|
|
38
|
+
*/
|
|
39
|
+
type TrimStart<S extends string, Chars extends string = Whitespace> = S extends `${Chars}${infer R}` ? TrimStart<R> : S;
|
|
40
|
+
/**
|
|
41
|
+
* 从字符串中移除后面的 空格 或 指定的字符
|
|
42
|
+
*/
|
|
43
|
+
type TrimEnd<S extends string, Chars extends string = Whitespace> = S extends `${infer L}${Chars}` ? TrimEnd<L> : S;
|
|
44
|
+
/**
|
|
45
|
+
* 从字符串中移除前面和后面的 空格 或 指定的字符
|
|
46
|
+
*/
|
|
47
|
+
type Trim<S extends string, Chars extends string = Whitespace> = TrimStart<TrimEnd<S, Chars>, Chars>;
|
|
48
|
+
/**
|
|
49
|
+
* 检查字符串 S 是否以 Target 开头
|
|
50
|
+
*/
|
|
51
|
+
type StartsWith<S extends string, Target extends string> = S extends `${Target}${infer _}` ? true : false;
|
|
52
|
+
/**
|
|
53
|
+
* 检查字符串 S 是否以 Target 结束
|
|
54
|
+
*/
|
|
55
|
+
type EndsWith<S extends string, Target extends string> = S extends `${infer _}${Target}` ? true : false;
|
|
56
|
+
/**
|
|
57
|
+
* 根据 SEP 拆分字符串
|
|
58
|
+
*/
|
|
59
|
+
type Split<S extends string, SEP extends string = never> = [
|
|
60
|
+
SEP
|
|
61
|
+
] extends [
|
|
62
|
+
never
|
|
63
|
+
] ? [
|
|
64
|
+
S
|
|
65
|
+
] : string extends SEP ? string[] : string extends S ? string[] : S extends `${infer First}${SEP}${infer Rest}` ? Rest extends "" ? [
|
|
66
|
+
First
|
|
67
|
+
] : [
|
|
68
|
+
First,
|
|
69
|
+
...Split<Rest, SEP>
|
|
70
|
+
] : S extends SEP ? [
|
|
71
|
+
] : [
|
|
72
|
+
S
|
|
73
|
+
];
|
|
74
|
+
/**
|
|
75
|
+
* 替换 S 字符串中匹配的 Pattern 为给定的 Replacement
|
|
76
|
+
*/
|
|
77
|
+
type Replace<S extends string, Pattern extends string, Repalcement extends string> = Pattern extends "" ? S : S extends `${infer F}${Pattern}${infer R}` ? `${F}${Repalcement}${R}` : S;
|
|
78
|
+
/**
|
|
79
|
+
* 替换 S 字符串中所有匹配的 Pattern 为给定的 Replacement
|
|
80
|
+
*/
|
|
81
|
+
type ReplaceAll<S extends string, Pattern extends string, Repalcement extends string> = Pattern extends "" ? S : S extends `${infer F}${Pattern}${infer R}` ? `${F}${Repalcement}${ReplaceAll<R, Pattern, Repalcement>}` : S;
|
|
82
|
+
/**
|
|
83
|
+
* 返回数据第一个元素的类型。
|
|
84
|
+
*/
|
|
85
|
+
type First<T extends any[]> = T extends [
|
|
86
|
+
] ? never : T[0];
|
|
87
|
+
/**
|
|
88
|
+
* 返回数组最后一个元素的类型。
|
|
89
|
+
*/
|
|
90
|
+
type Last<T extends any[]> = T extends [
|
|
91
|
+
...infer _,
|
|
92
|
+
infer L
|
|
93
|
+
] ? L : never;
|
|
94
|
+
/**
|
|
95
|
+
* 返回数组的前 N-1 项(N 为数组T的长度)以相同的顺序组成的数组。
|
|
96
|
+
*/
|
|
97
|
+
type Pop<T extends any[]> = T extends [
|
|
98
|
+
] ? [
|
|
99
|
+
] : T extends [
|
|
100
|
+
...infer R,
|
|
101
|
+
infer _
|
|
102
|
+
] ? R : never;
|
|
103
|
+
/**
|
|
104
|
+
* 将数组 T 递归为一维数组
|
|
105
|
+
*/
|
|
106
|
+
type Flatten<T extends any[]> = T extends [
|
|
107
|
+
infer FIRST,
|
|
108
|
+
...infer REST
|
|
109
|
+
] ? FIRST extends any[] ? [
|
|
110
|
+
...Flatten<FIRST>,
|
|
111
|
+
...Flatten<REST>
|
|
112
|
+
] : [
|
|
113
|
+
FIRST,
|
|
114
|
+
...Flatten<REST>
|
|
115
|
+
] : [
|
|
116
|
+
];
|
|
117
|
+
/**
|
|
118
|
+
* 将数组 T 与数组 U 合并为一个新数组
|
|
119
|
+
*/
|
|
120
|
+
type Concat<T extends readonly any[], U extends readonly any[]> = [
|
|
121
|
+
...T,
|
|
122
|
+
...U
|
|
123
|
+
];
|
|
124
|
+
/**
|
|
125
|
+
* 判断数组 T 是否包含元素 U
|
|
126
|
+
*/
|
|
127
|
+
type Includes<T extends readonly any[], U> = T extends [
|
|
128
|
+
infer F,
|
|
129
|
+
...infer R
|
|
130
|
+
] ? Equal<F, U> extends true ? true : Includes<R, U> : false;
|
|
131
|
+
/**
|
|
132
|
+
* 判断类型 T 是否为字面量对象
|
|
133
|
+
*/
|
|
134
|
+
type IsPlainObject<T> = T extends (...args: any) => any ? false : T extends Record<PropertyKey, any> ? Extract<keyof T, symbol> extends infer U ? [
|
|
135
|
+
U
|
|
136
|
+
] extends [
|
|
137
|
+
never
|
|
138
|
+
] ? true : false : never : false;
|
|
139
|
+
/**
|
|
140
|
+
* 获取类型 T 只读属性的键名
|
|
141
|
+
*/
|
|
142
|
+
type ReadonlyKeys<T> = {
|
|
143
|
+
[K in keyof T]-?: Equal<{
|
|
144
|
+
readonly [P in K]: T[K];
|
|
145
|
+
}, {
|
|
146
|
+
[P in K]: T[K];
|
|
147
|
+
}> extends true ? K : never;
|
|
148
|
+
}[keyof T];
|
|
149
|
+
/**
|
|
150
|
+
* 获取类型 T 必填属性的键名
|
|
151
|
+
*/
|
|
152
|
+
type RequiredKeys<T> = {
|
|
153
|
+
[K in keyof T]-?: {} extends {
|
|
154
|
+
[P in K]: T[K];
|
|
155
|
+
} ? never : K;
|
|
156
|
+
}[keyof T];
|
|
157
|
+
/**
|
|
158
|
+
* 获取类型 T 可选属性的键名
|
|
159
|
+
*/
|
|
160
|
+
type OptionalKeys<T> = {
|
|
161
|
+
[K in keyof T]-?: {} extends {
|
|
162
|
+
[P in K]: T[K];
|
|
163
|
+
} ? K : never;
|
|
164
|
+
}[keyof T];
|
|
165
|
+
/**
|
|
166
|
+
* 获取类型 T 的只读属性
|
|
167
|
+
*/
|
|
168
|
+
type GetReadonly<T> = {
|
|
169
|
+
[K in ReadonlyKeys<T>]: T[K];
|
|
170
|
+
};
|
|
171
|
+
/**
|
|
172
|
+
* 获取类型 T 的必填属性
|
|
173
|
+
*/
|
|
174
|
+
type GetRequired<T> = {
|
|
175
|
+
[K in keyof T as T[K] extends Required<T>[K] ? K : never]: T[K];
|
|
176
|
+
};
|
|
177
|
+
/**
|
|
178
|
+
* 获取类型 T 的可选属性
|
|
179
|
+
*/
|
|
180
|
+
type GetOptional<T> = {
|
|
181
|
+
[K in keyof T as T[K] extends Required<T>[K] ? never : K]: T[K];
|
|
182
|
+
};
|
|
183
|
+
/**
|
|
184
|
+
* 深度转换类型 T 的属性为只读
|
|
185
|
+
*/
|
|
186
|
+
type DeepReadonly<T> = {
|
|
187
|
+
readonly [K in keyof T]: keyof T[K] extends never ? T[K] : DeepReadonly<T[K]>;
|
|
188
|
+
};
|
|
189
|
+
/**
|
|
190
|
+
* 深度转化类型 T 的属性为必填
|
|
191
|
+
*/
|
|
192
|
+
type DeepRequired<T> = {
|
|
193
|
+
[K in keyof T]-?: keyof T[K] extends never ? T[K] : DeepRequired<T[K]>;
|
|
194
|
+
};
|
|
195
|
+
/**
|
|
196
|
+
* 深度转化类型 T 的属性为可选
|
|
197
|
+
*/
|
|
198
|
+
type DeepOptional<T> = {
|
|
199
|
+
[K in keyof T]?: keyof T[K] extends never ? T[K] : DeepOptional<T[K]>;
|
|
200
|
+
};
|
|
201
|
+
/**
|
|
202
|
+
* 根据对象 T 的 路径 K 获取值,如果解析 value 是 undefined 会以 defaultValue 取代。
|
|
203
|
+
*/
|
|
204
|
+
type GetValue<T, K extends string, Default = never> = K extends keyof T ? T[K] : K extends `${infer F}.${infer R}` ? F extends keyof T ? GetValue<T[F], R> : Default : Default;
|
|
205
|
+
}
|
package/index.d.ts
CHANGED
|
@@ -1,27 +1,204 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* 判断两个类型是否相等
|
|
3
|
+
*/
|
|
4
|
+
export type Equal<X, Y> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2 ? true : false;
|
|
5
|
+
/**
|
|
6
|
+
* 判断两个类型是否不相等
|
|
7
|
+
*/
|
|
8
|
+
export type NotEqual<X, Y> = true extends Equal<X, Y> ? false : true;
|
|
9
|
+
/**
|
|
10
|
+
* 判断类型是否为 any
|
|
11
|
+
*/
|
|
12
|
+
export type IsAny<T> = 0 extends 1 & T ? true : false;
|
|
13
|
+
/**
|
|
14
|
+
* 判断类型是否不为 any
|
|
15
|
+
*/
|
|
16
|
+
export type NotAny<T> = true extends IsAny<T> ? false : true;
|
|
17
|
+
/**
|
|
18
|
+
* 将类型 T 格式化输出,显示为单一对象类型
|
|
19
|
+
*/
|
|
20
|
+
export type Prettify<T> = {
|
|
21
|
+
[K in keyof T]: T[K];
|
|
22
|
+
} & {};
|
|
23
|
+
/**
|
|
24
|
+
* Prettify 的别名,用于测试类型结果
|
|
25
|
+
*/
|
|
26
|
+
export type Debug<T> = {
|
|
27
|
+
[K in keyof T]: T[K];
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* 根据条件 C 判断返回类型 T 或 F
|
|
31
|
+
*/
|
|
32
|
+
export type If<C extends boolean, T, F> = C extends true ? T : F;
|
|
33
|
+
type Whitespace = " " | "\n" | "\t";
|
|
34
|
+
/**
|
|
35
|
+
* 从字符串中移除前面的 空格 或 指定的字符
|
|
36
|
+
*/
|
|
37
|
+
export type TrimStart<S extends string, Chars extends string = Whitespace> = S extends `${Chars}${infer R}` ? TrimStart<R> : S;
|
|
38
|
+
/**
|
|
39
|
+
* 从字符串中移除后面的 空格 或 指定的字符
|
|
40
|
+
*/
|
|
41
|
+
export type TrimEnd<S extends string, Chars extends string = Whitespace> = S extends `${infer L}${Chars}` ? TrimEnd<L> : S;
|
|
42
|
+
/**
|
|
43
|
+
* 从字符串中移除前面和后面的 空格 或 指定的字符
|
|
44
|
+
*/
|
|
45
|
+
export type Trim<S extends string, Chars extends string = Whitespace> = TrimStart<TrimEnd<S, Chars>, Chars>;
|
|
46
|
+
/**
|
|
47
|
+
* 检查字符串 S 是否以 Target 开头
|
|
48
|
+
*/
|
|
49
|
+
export type StartsWith<S extends string, Target extends string> = S extends `${Target}${infer _}` ? true : false;
|
|
50
|
+
/**
|
|
51
|
+
* 检查字符串 S 是否以 Target 结束
|
|
52
|
+
*/
|
|
53
|
+
export type EndsWith<S extends string, Target extends string> = S extends `${infer _}${Target}` ? true : false;
|
|
54
|
+
/**
|
|
55
|
+
* 根据 SEP 拆分字符串
|
|
56
|
+
*/
|
|
57
|
+
export type Split<S extends string, SEP extends string = never> = [
|
|
58
|
+
SEP
|
|
59
|
+
] extends [
|
|
60
|
+
never
|
|
61
|
+
] ? [
|
|
62
|
+
S
|
|
63
|
+
] : string extends SEP ? string[] : string extends S ? string[] : S extends `${infer First}${SEP}${infer Rest}` ? Rest extends "" ? [
|
|
64
|
+
First
|
|
65
|
+
] : [
|
|
66
|
+
First,
|
|
67
|
+
...Split<Rest, SEP>
|
|
68
|
+
] : S extends SEP ? [
|
|
69
|
+
] : [
|
|
70
|
+
S
|
|
71
|
+
];
|
|
72
|
+
/**
|
|
73
|
+
* 替换 S 字符串中匹配的 Pattern 为给定的 Replacement
|
|
74
|
+
*/
|
|
75
|
+
export type Replace<S extends string, Pattern extends string, Repalcement extends string> = Pattern extends "" ? S : S extends `${infer F}${Pattern}${infer R}` ? `${F}${Repalcement}${R}` : S;
|
|
76
|
+
/**
|
|
77
|
+
* 替换 S 字符串中所有匹配的 Pattern 为给定的 Replacement
|
|
78
|
+
*/
|
|
79
|
+
export type ReplaceAll<S extends string, Pattern extends string, Repalcement extends string> = Pattern extends "" ? S : S extends `${infer F}${Pattern}${infer R}` ? `${F}${Repalcement}${ReplaceAll<R, Pattern, Repalcement>}` : S;
|
|
80
|
+
/**
|
|
81
|
+
* 返回数据第一个元素的类型。
|
|
82
|
+
*/
|
|
83
|
+
export type First<T extends any[]> = T extends [
|
|
84
|
+
] ? never : T[0];
|
|
85
|
+
/**
|
|
86
|
+
* 返回数组最后一个元素的类型。
|
|
87
|
+
*/
|
|
88
|
+
export type Last<T extends any[]> = T extends [
|
|
89
|
+
...infer _,
|
|
90
|
+
infer L
|
|
91
|
+
] ? L : never;
|
|
92
|
+
/**
|
|
93
|
+
* 返回数组的前 N-1 项(N 为数组T的长度)以相同的顺序组成的数组。
|
|
94
|
+
*/
|
|
95
|
+
export type Pop<T extends any[]> = T extends [
|
|
96
|
+
] ? [
|
|
97
|
+
] : T extends [
|
|
98
|
+
...infer R,
|
|
99
|
+
infer _
|
|
100
|
+
] ? R : never;
|
|
101
|
+
/**
|
|
102
|
+
* 将数组 T 递归为一维数组
|
|
103
|
+
*/
|
|
104
|
+
export type Flatten<T extends any[]> = T extends [
|
|
105
|
+
infer FIRST,
|
|
106
|
+
...infer REST
|
|
107
|
+
] ? FIRST extends any[] ? [
|
|
108
|
+
...Flatten<FIRST>,
|
|
109
|
+
...Flatten<REST>
|
|
110
|
+
] : [
|
|
111
|
+
FIRST,
|
|
112
|
+
...Flatten<REST>
|
|
113
|
+
] : [
|
|
114
|
+
];
|
|
115
|
+
/**
|
|
116
|
+
* 将数组 T 与数组 U 合并为一个新数组
|
|
117
|
+
*/
|
|
118
|
+
export type Concat<T extends readonly any[], U extends readonly any[]> = [
|
|
119
|
+
...T,
|
|
120
|
+
...U
|
|
121
|
+
];
|
|
122
|
+
/**
|
|
123
|
+
* 判断数组 T 是否包含元素 U
|
|
124
|
+
*/
|
|
125
|
+
export type Includes<T extends readonly any[], U> = T extends [
|
|
126
|
+
infer F,
|
|
127
|
+
...infer R
|
|
128
|
+
] ? Equal<F, U> extends true ? true : Includes<R, U> : false;
|
|
129
|
+
/**
|
|
130
|
+
* 判断类型 T 是否为字面量对象
|
|
131
|
+
*/
|
|
132
|
+
export type IsPlainObject<T> = T extends (...args: any) => any ? false : T extends Record<PropertyKey, any> ? Extract<keyof T, symbol> extends infer U ? [
|
|
133
|
+
U
|
|
134
|
+
] extends [
|
|
135
|
+
never
|
|
136
|
+
] ? true : false : never : false;
|
|
137
|
+
/**
|
|
138
|
+
* 获取类型 T 只读属性的键名
|
|
139
|
+
*/
|
|
140
|
+
export type ReadonlyKeys<T> = {
|
|
141
|
+
[K in keyof T]-?: Equal<{
|
|
142
|
+
readonly [P in K]: T[K];
|
|
143
|
+
}, {
|
|
144
|
+
[P in K]: T[K];
|
|
145
|
+
}> extends true ? K : never;
|
|
146
|
+
}[keyof T];
|
|
147
|
+
/**
|
|
148
|
+
* 获取类型 T 必填属性的键名
|
|
149
|
+
*/
|
|
150
|
+
export type RequiredKeys<T> = {
|
|
151
|
+
[K in keyof T]-?: {} extends {
|
|
152
|
+
[P in K]: T[K];
|
|
153
|
+
} ? never : K;
|
|
154
|
+
}[keyof T];
|
|
155
|
+
/**
|
|
156
|
+
* 获取类型 T 可选属性的键名
|
|
157
|
+
*/
|
|
158
|
+
export type OptionalKeys<T> = {
|
|
159
|
+
[K in keyof T]-?: {} extends {
|
|
160
|
+
[P in K]: T[K];
|
|
161
|
+
} ? K : never;
|
|
162
|
+
}[keyof T];
|
|
163
|
+
/**
|
|
164
|
+
* 获取类型 T 的只读属性
|
|
165
|
+
*/
|
|
166
|
+
export type GetReadonly<T> = {
|
|
167
|
+
[K in ReadonlyKeys<T>]: T[K];
|
|
168
|
+
};
|
|
169
|
+
/**
|
|
170
|
+
* 获取类型 T 的必填属性
|
|
171
|
+
*/
|
|
172
|
+
export type GetRequired<T> = {
|
|
173
|
+
[K in keyof T as T[K] extends Required<T>[K] ? K : never]: T[K];
|
|
174
|
+
};
|
|
175
|
+
/**
|
|
176
|
+
* 获取类型 T 的可选属性
|
|
177
|
+
*/
|
|
178
|
+
export type GetOptional<T> = {
|
|
179
|
+
[K in keyof T as T[K] extends Required<T>[K] ? never : K]: T[K];
|
|
180
|
+
};
|
|
181
|
+
/**
|
|
182
|
+
* 深度转换类型 T 的属性为只读
|
|
183
|
+
*/
|
|
184
|
+
export type DeepReadonly<T> = {
|
|
185
|
+
readonly [K in keyof T]: keyof T[K] extends never ? T[K] : DeepReadonly<T[K]>;
|
|
186
|
+
};
|
|
187
|
+
/**
|
|
188
|
+
* 深度转化类型 T 的属性为必填
|
|
189
|
+
*/
|
|
190
|
+
export type DeepRequired<T> = {
|
|
191
|
+
[K in keyof T]-?: keyof T[K] extends never ? T[K] : DeepRequired<T[K]>;
|
|
192
|
+
};
|
|
193
|
+
/**
|
|
194
|
+
* 深度转化类型 T 的属性为可选
|
|
195
|
+
*/
|
|
196
|
+
export type DeepOptional<T> = {
|
|
197
|
+
[K in keyof T]?: keyof T[K] extends never ? T[K] : DeepOptional<T[K]>;
|
|
198
|
+
};
|
|
199
|
+
/**
|
|
200
|
+
* 根据对象 T 的 路径 K 获取值,如果解析 value 是 undefined 会以 defaultValue 取代。
|
|
201
|
+
*/
|
|
202
|
+
export type GetValue<T, K extends string, Default = never> = K extends keyof T ? T[K] : K extends `${infer F}.${infer R}` ? F extends keyof T ? GetValue<T[F], R> : Default : Default;
|
|
2
203
|
|
|
3
|
-
|
|
4
|
-
export type { GetReadonlyKeys } from './src/00005-extreme-readonly-keys'
|
|
5
|
-
import('./src/00005-extreme-readonly-keys')
|
|
6
|
-
|
|
7
|
-
export type { DeepReadonly } from './src/00009-medium-deep-readonly'
|
|
8
|
-
import('./src/00009-medium-deep-readonly')
|
|
9
|
-
|
|
10
|
-
export type { TupleToUnion } from './src/00010-medium-tuple-to-union'
|
|
11
|
-
import('./src/00010-medium-tuple-to-union')
|
|
12
|
-
|
|
13
|
-
export type { TupleToObject } from './src/00011-easy-tuple-to-object'
|
|
14
|
-
import('./src/00011-easy-tuple-to-object')
|
|
15
|
-
|
|
16
|
-
export type { First } from './src/00014-easy-first'
|
|
17
|
-
import('./src/00014-easy-first')
|
|
18
|
-
|
|
19
|
-
export type { Last } from './src/00015-medium-last'
|
|
20
|
-
import('./src/00015-medium-last')
|
|
21
|
-
|
|
22
|
-
export type { Pop } from './src/00016-medium-pop'
|
|
23
|
-
import('./src/00016-medium-pop')
|
|
24
|
-
|
|
25
|
-
export type { UnionToTuple } from './src/00730-hard-union-to-tuple'
|
|
26
|
-
import('./src/00730-hard-union-to-tuple')
|
|
27
|
-
}
|
|
204
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "typescript-builtins-extended",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"description": "Collection of TypeScript Utility Types.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"typescript",
|
|
@@ -16,16 +16,28 @@
|
|
|
16
16
|
"url": "https://github.com/hayden-fr/typescript-builtins-extended.git"
|
|
17
17
|
},
|
|
18
18
|
"files": [
|
|
19
|
-
"src",
|
|
20
19
|
"index.d.ts",
|
|
20
|
+
"global.d.ts",
|
|
21
21
|
"tsconfig.json"
|
|
22
22
|
],
|
|
23
23
|
"types": "index.d.ts",
|
|
24
|
+
"exports": {
|
|
25
|
+
".": {
|
|
26
|
+
"types": "./index.d.ts"
|
|
27
|
+
},
|
|
28
|
+
"./global": {
|
|
29
|
+
"types": "./global.d.ts"
|
|
30
|
+
}
|
|
31
|
+
},
|
|
24
32
|
"author": "hayden <hayden.mike.zhang@gmail.com>",
|
|
25
33
|
"devDependencies": {
|
|
26
34
|
"typescript": "^5.9.2"
|
|
27
35
|
},
|
|
28
36
|
"scripts": {
|
|
37
|
+
"build": "pnpm run build:dts && pnpm run build:global-dts && pnpm run build:format",
|
|
38
|
+
"build:dts": "pnpx dts-bundle-generator --config ./build.json",
|
|
39
|
+
"build:global-dts": "node scripts/generate-global-dts.mjs",
|
|
40
|
+
"build:format": "pnpx prettier --write index.d.ts global.d.ts",
|
|
29
41
|
"test": "tsc --noEmit"
|
|
30
42
|
}
|
|
31
43
|
}
|
package/tsconfig.json
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
// - `CommonJS` is too outdated
|
|
14
14
|
// - the ecosystem hasn't fully caught up with `Node16`/`NodeNext`
|
|
15
15
|
// This recommendation includes environments like Vitest, Vite Config File, Vite SSR, etc.
|
|
16
|
-
"module": "
|
|
16
|
+
"module": "esnext",
|
|
17
17
|
|
|
18
18
|
// We expect users to use bundlers.
|
|
19
19
|
// So here we enable some resolution features that are only available in bundlers.
|
|
@@ -24,6 +24,8 @@
|
|
|
24
24
|
// It helps to avoid mysterious errors such as `Cannot redeclare block-scoped variable 'name`.
|
|
25
25
|
// https://www.totaltypescript.com/cannot-redeclare-block-scoped-variable#solution-3-your-module-isnt-a-module
|
|
26
26
|
"moduleDetection": "force",
|
|
27
|
+
"declaration": true,
|
|
28
|
+
"emitDeclarationOnly": true,
|
|
27
29
|
|
|
28
30
|
// `"noImplicitThis": true` is part of `strict`
|
|
29
31
|
// Added again here in case some users decide to disable `strict`.
|
|
@@ -32,9 +34,8 @@
|
|
|
32
34
|
"strict": true,
|
|
33
35
|
|
|
34
36
|
// supports ES2016+
|
|
35
|
-
"target": "
|
|
37
|
+
"target": "esnext",
|
|
36
38
|
|
|
37
|
-
|
|
38
|
-
"skipLibCheck": true,
|
|
39
|
+
"newLine": "lf"
|
|
39
40
|
}
|
|
40
41
|
}
|
package/README.zh-CN.md
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
# Typescript Utilities
|
|
2
|
-
|
|
3
|
-
[English](README.md) | 简体中文
|
|
4
|
-
|
|
5
|
-
为 typescript 提供全局范围的类型转换工具,与其他工具不同,`typescript-builtins-extended` 不提供任何 js 代码,专注于 typescript 的类型转换。并且可以像使用 `Omit` `Pick` 等内置实用程序类型一样直接使用,无需额外导入。
|
|
6
|
-
|
|
7
|
-
实用程序类型与其实现方式来源于 [type-challenges](https://github.com/type-challenges/type-challenges.git)
|
|
8
|
-
|
|
9
|
-
## 使用
|
|
10
|
-
|
|
11
|
-
将下面的代码添加到 `d.ts` 声明文件中
|
|
12
|
-
|
|
13
|
-
```ts
|
|
14
|
-
/// <reference types="typescript-builtins-extended" />
|
|
15
|
-
```
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
// ============= Test Cases =============
|
|
2
|
-
import type { Equal, Expect } from './test-utils'
|
|
3
|
-
|
|
4
|
-
type cases = [
|
|
5
|
-
Expect<Equal<'title', GetReadonlyKeys<Todo1>>>,
|
|
6
|
-
Expect<Equal<'title' | 'description', GetReadonlyKeys<Todo2>>>,
|
|
7
|
-
]
|
|
8
|
-
|
|
9
|
-
interface Todo1 {
|
|
10
|
-
readonly title: string
|
|
11
|
-
description: string
|
|
12
|
-
completed: boolean
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
interface Todo2 {
|
|
16
|
-
readonly title: string
|
|
17
|
-
readonly description: string
|
|
18
|
-
completed?: boolean
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
// ============= Your Code Here =============
|
|
23
|
-
// Implemented by https://github.com/type-challenges/type-challenges/issues/139
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Implement a generic `GetReadonlyKeys<T>` that returns a union of the readonly keys of an Object.
|
|
27
|
-
*
|
|
28
|
-
* 实现泛型 `GetReadonlyKeys<T>`,`GetReadonlyKeys<T>` 返回由对象 T 所有只读属性的键组成的联合类型。
|
|
29
|
-
*/
|
|
30
|
-
export type GetReadonlyKeys<
|
|
31
|
-
T,
|
|
32
|
-
U extends Readonly<T> = Readonly<T>,
|
|
33
|
-
K extends keyof T = keyof T
|
|
34
|
-
> = K extends keyof T ? Equal<Pick<T, K>, Pick<U, K>> extends true ? K : never : never;
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
// ============= Test Cases =============
|
|
2
|
-
import type { Equal, Expect } from './test-utils'
|
|
3
|
-
|
|
4
|
-
type cases = [
|
|
5
|
-
Expect<Equal<DeepReadonly<X1>, Expected1>>,
|
|
6
|
-
Expect<Equal<DeepReadonly<X2>, Expected2>>,
|
|
7
|
-
]
|
|
8
|
-
|
|
9
|
-
type X1 = {
|
|
10
|
-
a: () => 22
|
|
11
|
-
b: string
|
|
12
|
-
c: {
|
|
13
|
-
d: boolean
|
|
14
|
-
e: {
|
|
15
|
-
g: {
|
|
16
|
-
h: {
|
|
17
|
-
i: true
|
|
18
|
-
j: 'string'
|
|
19
|
-
}
|
|
20
|
-
k: 'hello'
|
|
21
|
-
}
|
|
22
|
-
l: [
|
|
23
|
-
'hi',
|
|
24
|
-
{
|
|
25
|
-
m: ['hey']
|
|
26
|
-
},
|
|
27
|
-
]
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
type X2 = { a: string } | { b: number }
|
|
33
|
-
|
|
34
|
-
type Expected1 = {
|
|
35
|
-
readonly a: () => 22
|
|
36
|
-
readonly b: string
|
|
37
|
-
readonly c: {
|
|
38
|
-
readonly d: boolean
|
|
39
|
-
readonly e: {
|
|
40
|
-
readonly g: {
|
|
41
|
-
readonly h: {
|
|
42
|
-
readonly i: true
|
|
43
|
-
readonly j: 'string'
|
|
44
|
-
}
|
|
45
|
-
readonly k: 'hello'
|
|
46
|
-
}
|
|
47
|
-
readonly l: readonly [
|
|
48
|
-
'hi',
|
|
49
|
-
{
|
|
50
|
-
readonly m: readonly ['hey']
|
|
51
|
-
},
|
|
52
|
-
]
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
type Expected2 = { readonly a: string } | { readonly b: number }
|
|
58
|
-
|
|
59
|
-
// ============= Your Code Here =============
|
|
60
|
-
// Implemented by https://github.com/type-challenges/type-challenges/issues/13716
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Implement a generic `DeepReadonly<T>` which make every parameter of an object - and its sub-objects recursively - readonly.
|
|
64
|
-
*
|
|
65
|
-
* 实现一个泛型 `DeepReadonly<T>`,它将对象的每个参数及其子对象递归地设为只读。
|
|
66
|
-
*/
|
|
67
|
-
export type DeepReadonly<T> = {
|
|
68
|
-
readonly [P in keyof T]: keyof T[P] extends never ? T[P] : DeepReadonly<T[P]>
|
|
69
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
// ============= Test Cases =============
|
|
2
|
-
import type { Equal, Expect } from './test-utils'
|
|
3
|
-
|
|
4
|
-
type cases = [
|
|
5
|
-
Expect<Equal<TupleToUnion<[123, '456', true]>, 123 | '456' | true>>,
|
|
6
|
-
Expect<Equal<TupleToUnion<[123]>, 123>>,
|
|
7
|
-
]
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
// ============= Your Code Here =============
|
|
11
|
-
// Implemented by https://github.com/type-challenges/type-challenges/issues/7
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Implement a generic `TupleToUnion<T>` which covers the values of a tuple to its values union.
|
|
15
|
-
*
|
|
16
|
-
* 实现泛型 `TupleToUnion<T>`,它返回元组所有值的合集。
|
|
17
|
-
*/
|
|
18
|
-
export type TupleToUnion<T> = T extends Array<infer ITEMS> ? ITEMS : never
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
// ============= Test Cases =============
|
|
2
|
-
import type { Equal, Expect } from './test-utils'
|
|
3
|
-
|
|
4
|
-
const tuple = ['tesla', 'model 3', 'model X', 'model Y'] as const
|
|
5
|
-
const tupleNumber = [1, 2, 3, 4] as const
|
|
6
|
-
const sym1 = Symbol(1)
|
|
7
|
-
const sym2 = Symbol(2)
|
|
8
|
-
const tupleSymbol = [sym1, sym2] as const
|
|
9
|
-
const tupleMix = [1, '2', 3, '4', sym1] as const
|
|
10
|
-
|
|
11
|
-
type cases = [
|
|
12
|
-
Expect<Equal<TupleToObject<typeof tuple>, { 'tesla': 'tesla', 'model 3': 'model 3', 'model X': 'model X', 'model Y': 'model Y' }>>,
|
|
13
|
-
Expect<Equal<TupleToObject<typeof tupleNumber>, { 1: 1, 2: 2, 3: 3, 4: 4 }>>,
|
|
14
|
-
Expect<Equal<TupleToObject<typeof tupleSymbol>, { [sym1]: typeof sym1, [sym2]: typeof sym2 }>>,
|
|
15
|
-
Expect<Equal<TupleToObject<typeof tupleMix>, { 1: 1, '2': '2', 3: 3, '4': '4', [sym1]: typeof sym1 }>>,
|
|
16
|
-
]
|
|
17
|
-
|
|
18
|
-
// @ts-expect-error
|
|
19
|
-
type error = TupleToObject<[[1, 2], {}]>
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
// ============= Your Code Here =============
|
|
23
|
-
// Implemented by https://github.com/type-challenges/type-challenges/issues/5896
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Given an array, transform it into an object type and the key/value must be in the provided array.
|
|
27
|
-
*
|
|
28
|
-
* 将一个元组类型转换为对象类型,这个对象类型的键/值和元组中的元素对应。
|
|
29
|
-
*/
|
|
30
|
-
export type TupleToObject<T extends readonly (string | symbol | number)[]> = {
|
|
31
|
-
[P in T[number]]: P
|
|
32
|
-
}
|
package/src/00014-easy-first.ts
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
// ============= Test Cases =============
|
|
2
|
-
import type { Equal, Expect } from './test-utils'
|
|
3
|
-
|
|
4
|
-
type cases = [
|
|
5
|
-
Expect<Equal<First<[3, 2, 1]>, 3>>,
|
|
6
|
-
Expect<Equal<First<[() => 123, { a: string }]>, () => 123>>,
|
|
7
|
-
Expect<Equal<First<[]>, never>>,
|
|
8
|
-
Expect<Equal<First<[undefined]>, undefined>>,
|
|
9
|
-
]
|
|
10
|
-
|
|
11
|
-
type errors = [
|
|
12
|
-
// @ts-expect-error
|
|
13
|
-
First<'notArray'>,
|
|
14
|
-
// @ts-expect-error
|
|
15
|
-
First<{ 0: 'arrayLike' }>,
|
|
16
|
-
]
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
// ============= Your Code Here =============
|
|
20
|
-
// Implemented by https://github.com/type-challenges/type-challenges/issues/16315
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Implement a generic `First<T>` that takes an Array T and returns its first element's type.
|
|
24
|
-
*
|
|
25
|
-
* 实现一个 `First<T>` 泛型,它接受一个数组T并返回它的第一个元素的类型。
|
|
26
|
-
*/
|
|
27
|
-
export type First<T extends any[]> = T extends [] ? never : T[0]
|
package/src/00015-medium-last.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
// ============= Test Cases =============
|
|
2
|
-
import type { Equal, Expect } from './test-utils'
|
|
3
|
-
|
|
4
|
-
type cases = [
|
|
5
|
-
Expect<Equal<Last<[]>, never>>,
|
|
6
|
-
Expect<Equal<Last<[2]>, 2>>,
|
|
7
|
-
Expect<Equal<Last<[3, 2, 1]>, 1>>,
|
|
8
|
-
Expect<Equal<Last<[() => 123, { a: string }]>, { a: string }>>,
|
|
9
|
-
]
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
// ============= Your Code Here =============
|
|
13
|
-
// Implemented by https://github.com/type-challenges/type-challenges/issues/38
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Implement a generic `Last<T>` that takes an Array T and returns its last element.
|
|
17
|
-
*
|
|
18
|
-
* 实现一个 `Last<T>` 泛型,它接受一个数组T并返回其最后一个元素的类型。
|
|
19
|
-
*/
|
|
20
|
-
export type Last<T extends any[]> = T extends [...infer _, infer L] ? L : never
|
package/src/00016-medium-pop.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
// ============= Test Cases =============
|
|
2
|
-
import type { Equal, Expect } from './test-utils'
|
|
3
|
-
|
|
4
|
-
type cases = [
|
|
5
|
-
Expect<Equal<Pop<[3, 2, 1]>, [3, 2]>>,
|
|
6
|
-
Expect<Equal<Pop<['a', 'b', 'c', 'd']>, ['a', 'b', 'c']>>,
|
|
7
|
-
Expect<Equal<Pop<[]>, []>>,
|
|
8
|
-
]
|
|
9
|
-
|
|
10
|
-
// ============= Your Code Here =============
|
|
11
|
-
// Implemented by https://github.com/type-challenges/type-challenges/issues/37295
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Implement a generic `Pop<T>` that takes an Array T and returns an Array without it's last element.
|
|
15
|
-
*
|
|
16
|
-
* 实现一个泛型 `Pop<T>`,它接受一个数组T,并返回一个由数组T的前 N-1 项(N 为数组T的长度)以相同的顺序组成的数组。
|
|
17
|
-
*/
|
|
18
|
-
export type Pop<T extends any[]> = T extends []
|
|
19
|
-
? []
|
|
20
|
-
: T extends [...infer R, infer _]
|
|
21
|
-
? R
|
|
22
|
-
: never
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
// ============= Test Cases =============
|
|
2
|
-
import type { Equal, Expect } from './test-utils'
|
|
3
|
-
|
|
4
|
-
type ExtractValuesOfTuple<T extends any[]> = T[keyof T & number]
|
|
5
|
-
|
|
6
|
-
type cases = [
|
|
7
|
-
Expect<Equal<UnionToTuple<'a' | 'b'>['length'], 2>>,
|
|
8
|
-
Expect<Equal<ExtractValuesOfTuple<UnionToTuple<'a' | 'b'>>, 'a' | 'b'>>,
|
|
9
|
-
Expect<Equal<ExtractValuesOfTuple<UnionToTuple<'a'>>, 'a'>>,
|
|
10
|
-
Expect<Equal<ExtractValuesOfTuple<UnionToTuple<any>>, any>>,
|
|
11
|
-
Expect<Equal<ExtractValuesOfTuple<UnionToTuple<undefined | void | 1>>, void | 1>>,
|
|
12
|
-
Expect<Equal<ExtractValuesOfTuple<UnionToTuple<any | 1>>, any | 1>>,
|
|
13
|
-
Expect<Equal<ExtractValuesOfTuple<UnionToTuple<any | 1>>, any>>,
|
|
14
|
-
Expect<Equal<ExtractValuesOfTuple<UnionToTuple<'d' | 'f' | 1 | never>>, 'f' | 'd' | 1>>,
|
|
15
|
-
Expect<Equal<ExtractValuesOfTuple<UnionToTuple<[{ a: 1 }] | 1>>, [{ a: 1 }] | 1>>,
|
|
16
|
-
Expect<Equal<ExtractValuesOfTuple<UnionToTuple<never>>, never>>,
|
|
17
|
-
Expect<Equal<ExtractValuesOfTuple<UnionToTuple<'a' | 'b' | 'c' | 1 | 2 | 'd' | 'e' | 'f' | 'g'>>, 'f' | 'e' | 1 | 2 | 'g' | 'c' | 'd' | 'a' | 'b'>>,
|
|
18
|
-
]
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
// ============= Your Code Here =============
|
|
22
|
-
// Implemented by https://github.com/type-challenges/type-challenges/issues/737
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* UnionToIntersection<{ foo: string } | { bar: string }> =
|
|
26
|
-
* { foo: string } & { bar: string }.
|
|
27
|
-
*/
|
|
28
|
-
type UnionToIntersection<U> = (
|
|
29
|
-
U extends unknown ? (arg: U) => 0 : never
|
|
30
|
-
) extends (arg: infer I) => 0
|
|
31
|
-
? I
|
|
32
|
-
: never;
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* LastInUnion<1 | 2> = 2.
|
|
36
|
-
*/
|
|
37
|
-
type LastInUnion<U> = UnionToIntersection<
|
|
38
|
-
U extends unknown ? (x: U) => 0 : never
|
|
39
|
-
> extends (x: infer L) => 0
|
|
40
|
-
? L
|
|
41
|
-
: never;
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Implement a type, UnionToTuple, that converts a union to a tuple.
|
|
45
|
-
*
|
|
46
|
-
* 将联合转换为元组的类型。
|
|
47
|
-
*
|
|
48
|
-
* UnionToTuple<1 | 2> = [1, 2].
|
|
49
|
-
*/
|
|
50
|
-
export type UnionToTuple<U, Last = LastInUnion<U>> = [U] extends [never]
|
|
51
|
-
? []
|
|
52
|
-
: [...UnionToTuple<Exclude<U, Last>>, Last];
|
package/src/test-utils.ts
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
export type Expect<T extends true> = T
|
|
2
|
-
export type ExpectTrue<T extends true> = T
|
|
3
|
-
export type ExpectFalse<T extends false> = T
|
|
4
|
-
export type IsTrue<T extends true> = T
|
|
5
|
-
export type IsFalse<T extends false> = T
|
|
6
|
-
|
|
7
|
-
export type Equal<X, Y> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2
|
|
8
|
-
? true
|
|
9
|
-
: false
|
|
10
|
-
export type NotEqual<X, Y> = true extends Equal<X, Y> ? false : true
|
|
11
|
-
|
|
12
|
-
// https://stackoverflow.com/questions/49927523/disallow-call-with-any/49928360#49928360
|
|
13
|
-
export type IsAny<T> = 0 extends 1 & T ? true : false
|
|
14
|
-
export type NotAny<T> = true extends IsAny<T> ? false : true
|
|
15
|
-
|
|
16
|
-
export type Debug<T> = { [K in keyof T]: T[K] }
|
|
17
|
-
export type MergeInsertions<T> = T extends object ? { [K in keyof T]: MergeInsertions<T[K]> } : T
|
|
18
|
-
|
|
19
|
-
export type Alike<X, Y> = Equal<MergeInsertions<X>, MergeInsertions<Y>>
|
|
20
|
-
|
|
21
|
-
export type ExpectExtends<VALUE, EXPECTED> = EXPECTED extends VALUE ? true : false
|
|
22
|
-
export type ExpectValidArgs<
|
|
23
|
-
FUNC extends (...args: any[]) => any,
|
|
24
|
-
ARGS extends any[]
|
|
25
|
-
> = ARGS extends Parameters<FUNC> ? true : false
|
|
26
|
-
|
|
27
|
-
export type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (
|
|
28
|
-
k: infer I
|
|
29
|
-
) => void
|
|
30
|
-
? I
|
|
31
|
-
: never
|