Skip to content

Commit 79e1f17

Browse files
committed
feat(types): add types, set deprecated types
add: - TupleHead - TupleTail - TupleLast - TupleRemoveLast - TupleUnshift - TuplePush - TupleConcat deprecated: - Head - Tail - Unshift - Last - Push - Concat
1 parent c17f9ab commit 79e1f17

File tree

4 files changed

+293
-1
lines changed

4 files changed

+293
-1
lines changed

packages/types/src/lib/common.ts

+19-1
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,23 @@
33
// ref: https://zhuanlan.zhihu.com/p/38687656
44
// original ref: https://github.com/microsoft/typescript/pull/24897
55
// dependencies typescript >= 3.1
6+
/**
7+
* @deprecated use `TupleHead` instead
8+
*/
69
export type Head<Tuple extends any[]> = Tuple extends [infer H, ...any[]] ? H : never
10+
/**
11+
* @deprecated use `TupleTail` instead
12+
*/
713
export type Tail<Tuple extends any[]> = ((...x: Tuple) => void) extends ((h: any, ...rest: infer R) => void) ? R : never
14+
/**
15+
* @deprecated use `TupleUnshift` instead
16+
*/
817
export type Unshift<
918
Tuple extends any[],
1019
Element> = ((h: Element, ...tuple: Tuple) => void) extends (...x: infer R) => void ? R : never
20+
/**
21+
* @deprecated use `TupleLast` instead
22+
*/
1123
export type Last<Tuple extends any[]> = {
1224
1: Tuple[0],
1325
0: Last<Tail<Tuple>>,
@@ -20,18 +32,23 @@ type Reverse_<Tuple extends any[], Result extends any[]> = {
2032
}[Tuple extends [] ? 1 : 0]
2133

2234
export type ToTuple<T> = T extends any[] ? T : any[]
35+
/**
36+
* @deprecated use `TuplePush` instead
37+
*/
2338
export type Push<
2439
Tuple extends any[],
2540
Element,
2641
R = Reverse<Tuple>,
2742
T extends any[] = ToTuple<R>
2843
> = Reverse<Unshift<T, Element>>
2944

45+
/**
46+
* @deprecated use `TupleConcat` instead
47+
*/
3048
export type Concat<
3149
Tuple1 extends any[],
3250
Tuple2 extends any[],
3351
R = Reverse<Tuple1>, T extends any[] = ToTuple<R>> = Concat_<T, Tuple2>
34-
3552
type Concat_<Tuple1 extends any[], Tuple2 extends any[]> = {
3653
1: Reverse<Tuple1>,
3754
0: Concat_<Unshift<Tuple1, Head<Tuple2>>, Tail<Tuple2>>,
@@ -79,3 +96,4 @@ export type Invert<T extends Record<PropertyKey, PropertyKey>> = {
7996
export type Equals<X, Y> = (<T>() => T extends X ? 1 : 2) extends (<T>() => T extends Y ? 1 : 2)
8097
? true
8198
: false
99+

packages/types/src/lib/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ export * from './common'
44
export * from './data'
55
export * from './npm-pkg'
66
export * from './union2tuple'
7+
export * from './tuple'
78

packages/types/src/lib/tuple.ts

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/* eslint-disable @typescript-eslint/no-explicit-any */
2+
3+
// ref: https://zhuanlan.zhihu.com/p/38687656
4+
5+
/** Get the first element */
6+
export type TupleHead<T extends any[]> = T[0]
7+
8+
/** Remove the first element */
9+
export type TupleTail<T extends any[]> = ((...t: T) => void) extends (x: any, ...t: infer R) => void ? R : never
10+
11+
/** Get the last element */
12+
export type TupleLast<T extends any[]> = T[TupleTail<T>['length']]
13+
14+
/** Remove the last element */
15+
export type TupleRemoveLast<T extends any[]> = TypeAssert<Overwrite<TupleTail<T>, T>, any[]>
16+
17+
/** Insert element at first */
18+
export type TupleUnshift<T extends any[], X> = ((x: X, ...t: T) => void) extends (...t: infer R) => void ? R : never
19+
20+
/** Append element at last */
21+
export type TuplePush<T extends any[], X> = TypeAssert<Overwrite<TupleUnshift<T, any>, T & { [x: string]: X }>, any[]>
22+
23+
/** Concat two tuples */
24+
export type TupleConcat<A extends any[], B extends any[]> = {
25+
1: A,
26+
0: TupleConcat<TuplePush<A, B[0]>, TupleTail<B>>,
27+
}[B extends [] ? 1 : 0]
28+
29+
// 用到的 helper 类型,简化代码和解决某些情况下的类型错误
30+
export type TypeAssert<T, A> = T extends A ? T : never
31+
// @ts-expect-error
32+
export type Overwrite<T, S extends any> = { [P in keyof T]: S[P] }
33+

packages/types/test/10.tuple.test.ts

+240
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
/* eslint-disable node/no-extraneous-import */
2+
import {
3+
basename,
4+
join,
5+
} from '@waiting/shared-core'
6+
import * as assert from 'power-assert'
7+
8+
import {
9+
Equals,
10+
TupleHead,
11+
TupleTail,
12+
TupleLast,
13+
TupleRemoveLast,
14+
TupleUnshift,
15+
TuplePush,
16+
TupleConcat,
17+
} from '../src/index'
18+
19+
20+
const filename = basename(__filename)
21+
22+
describe(filename, () => {
23+
24+
describe('should TupleHead works', () => {
25+
it('normal', () => {
26+
type Foo = [string, number, string]
27+
type T1 = TupleHead<Foo>
28+
type ExpectType = string
29+
const ret: Equals<T1, ExpectType> = true
30+
})
31+
it('empty', () => {
32+
type Foo = []
33+
type T1 = TupleHead<Foo>
34+
type ExpectType = undefined
35+
const ret: Equals<T1, ExpectType> = true
36+
})
37+
it('unknown', () => {
38+
type Foo = [unknown]
39+
type T1 = TupleHead<Foo>
40+
type ExpectType = unknown
41+
const ret: Equals<T1, ExpectType> = true
42+
})
43+
it('any', () => {
44+
type Foo = [any]
45+
type T1 = TupleHead<Foo>
46+
type ExpectType = any
47+
const ret: Equals<T1, ExpectType> = true
48+
})
49+
})
50+
51+
describe('should TupleTail works', () => {
52+
it('normal', () => {
53+
type Foo = [string, number, string]
54+
type T1 = TupleTail<Foo>
55+
type ExpectType = [number, string]
56+
const ret: Equals<T1, ExpectType> = true
57+
})
58+
it('empty', () => {
59+
type Foo = []
60+
type T1 = TupleTail<Foo>
61+
type ExpectType = []
62+
const ret: Equals<T1, ExpectType> = true
63+
})
64+
it('unknown[]', () => {
65+
type Foo = unknown[]
66+
type T1 = TupleTail<Foo>
67+
type ExpectType = unknown[]
68+
const ret: Equals<T1, ExpectType> = true
69+
})
70+
it('any', () => {
71+
type Foo = [any]
72+
type T1 = TupleTail<Foo>
73+
type ExpectType = []
74+
const ret: Equals<T1, ExpectType> = true
75+
})
76+
it('any[]', () => {
77+
type Foo = any[]
78+
type T1 = TupleTail<Foo>
79+
type ExpectType = any[]
80+
const ret: Equals<T1, ExpectType> = true
81+
})
82+
})
83+
84+
describe('should TupleLast works', () => {
85+
it('normal', () => {
86+
type Foo = [string, number, string]
87+
type T1 = TupleLast<Foo>
88+
type ExpectType = string
89+
const ret: Equals<T1, ExpectType> = true
90+
})
91+
it('empty', () => {
92+
type Foo = []
93+
type T1 = TupleLast<Foo>
94+
type ExpectType = undefined
95+
const ret: Equals<T1, ExpectType> = true
96+
})
97+
it('unknown', () => {
98+
type Foo = [unknown]
99+
type T1 = TupleLast<Foo>
100+
type ExpectType = unknown
101+
const ret: Equals<T1, ExpectType> = true
102+
})
103+
it('any', () => {
104+
type Foo = [any]
105+
type T1 = TupleLast<Foo>
106+
type ExpectType = any
107+
const ret: Equals<T1, ExpectType> = true
108+
})
109+
})
110+
111+
describe('should TupleRemoveLast works', () => {
112+
it('normal', () => {
113+
type Foo = [string, number, string]
114+
type T1 = TupleRemoveLast<Foo>
115+
type ExpectType = [string, number]
116+
const ret: Equals<T1, ExpectType> = true
117+
})
118+
it('empty', () => {
119+
type Foo = []
120+
type T1 = TupleRemoveLast<Foo>
121+
type ExpectType = []
122+
const ret: Equals<T1, ExpectType> = true
123+
})
124+
it('unknown', () => {
125+
type Foo = [unknown]
126+
type T1 = TupleRemoveLast<Foo>
127+
type ExpectType = []
128+
const ret: Equals<T1, ExpectType> = true
129+
})
130+
it('any', () => {
131+
type Foo = [any]
132+
type T1 = TupleRemoveLast<Foo>
133+
type ExpectType = []
134+
const ret: Equals<T1, ExpectType> = true
135+
})
136+
})
137+
138+
139+
describe('should TupleUnshift works', () => {
140+
it('normal', () => {
141+
type Foo = [string, number, string]
142+
type T1 = TupleUnshift<Foo, bigint>
143+
type ExpectType = [bigint, string, number, string]
144+
const ret: Equals<T1, ExpectType> = true
145+
})
146+
it('empty', () => {
147+
type Foo = []
148+
type T1 = TupleUnshift<Foo, bigint>
149+
type ExpectType = [bigint]
150+
const ret: Equals<T1, ExpectType> = true
151+
})
152+
it('unknown', () => {
153+
type Foo = [unknown]
154+
type T1 = TupleUnshift<Foo, bigint>
155+
type ExpectType = [bigint, unknown]
156+
const ret: Equals<T1, ExpectType> = true
157+
})
158+
it('any', () => {
159+
type Foo = [any]
160+
type T1 = TupleUnshift<Foo, bigint>
161+
type ExpectType = [bigint, any]
162+
const ret: Equals<T1, ExpectType> = true
163+
})
164+
it('mixed', () => {
165+
type Foo = [1, 2, 'foo']
166+
type T1 = TupleUnshift<Foo, 3>
167+
type ExpectType = [3, 1, 2, 'foo']
168+
const ret: Equals<T1, ExpectType> = true
169+
})
170+
})
171+
172+
describe('should TuplePush works', () => {
173+
it('normal', () => {
174+
type Foo = [string, number, string]
175+
type T1 = TuplePush<Foo, bigint>
176+
type ExpectType = [string, number, string, bigint]
177+
const ret: Equals<T1, ExpectType> = true
178+
})
179+
it('empty', () => {
180+
type Foo = []
181+
type T1 = TuplePush<Foo, bigint>
182+
type ExpectType = [bigint]
183+
const ret: Equals<T1, ExpectType> = true
184+
})
185+
it('unknown', () => {
186+
type Foo = [unknown]
187+
type T1 = TuplePush<Foo, bigint>
188+
type ExpectType = [unknown, bigint]
189+
const ret: Equals<T1, ExpectType> = true
190+
})
191+
it('any', () => {
192+
type Foo = [any]
193+
type T1 = TuplePush<Foo, bigint>
194+
type ExpectType = [any, bigint]
195+
const ret: Equals<T1, ExpectType> = true
196+
})
197+
it('mixed', () => {
198+
type Foo = [1, 2, 'foo']
199+
type T1 = TuplePush<Foo, 3>
200+
type ExpectType = [1, 2, 'foo', 3]
201+
const ret: Equals<T1, ExpectType> = true
202+
})
203+
})
204+
205+
describe('should TupleConcat works', () => {
206+
it('normal', () => {
207+
type Foo = [string, number, string]
208+
type T1 = TupleConcat<Foo, [bigint]>
209+
type ExpectType = [string, number, string, bigint]
210+
const ret: Equals<T1, ExpectType> = true
211+
})
212+
it('empty', () => {
213+
type Foo = []
214+
type T1 = TupleConcat<Foo, [bigint]>
215+
type ExpectType = [bigint]
216+
const ret: Equals<T1, ExpectType> = true
217+
})
218+
it('unknown', () => {
219+
type Foo = [unknown]
220+
type T1 = TupleConcat<Foo, [bigint]>
221+
type ExpectType = [unknown, bigint]
222+
const ret: Equals<T1, ExpectType> = true
223+
})
224+
it('any', () => {
225+
type Foo = [any]
226+
type T1 = TupleConcat<Foo, [bigint]>
227+
type ExpectType = [any, bigint]
228+
const ret: Equals<T1, ExpectType> = true
229+
})
230+
it('mixed', () => {
231+
type Foo = [1, 2, 'foo']
232+
type T1 = TupleConcat<Foo, [3, 'bar', 'foo']>
233+
type ExpectType = [1, 2, 'foo', 3, 'bar', 'foo']
234+
const ret: Equals<T1, ExpectType> = true
235+
})
236+
})
237+
238+
239+
})
240+

0 commit comments

Comments
 (0)