@zimi/remote 0.2.1 → 0.2.4

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.
Files changed (115) hide show
  1. package/LICENSE.md +21 -21
  2. package/README.md +289 -285
  3. package/dist/adaptor.d.mts +33 -0
  4. package/dist/adaptor.d.ts +5 -4
  5. package/dist/adaptor.js +1 -1
  6. package/dist/adaptor.js.map +1 -1
  7. package/dist/adaptor.mjs +1 -0
  8. package/dist/adaptor.mjs.map +1 -0
  9. package/dist/adaptors/dao3/client.d.mts +39 -0
  10. package/dist/adaptors/dao3/client.d.ts +5 -3
  11. package/dist/adaptors/dao3/client.js +1 -44
  12. package/dist/adaptors/dao3/client.js.map +1 -1
  13. package/dist/adaptors/dao3/client.mjs +2 -0
  14. package/dist/adaptors/dao3/client.mjs.map +1 -0
  15. package/dist/adaptors/dao3/server.d.mts +82 -0
  16. package/dist/adaptors/dao3/server.d.ts +5 -3
  17. package/dist/adaptors/dao3/server.js +1 -104
  18. package/dist/adaptors/dao3/server.js.map +1 -1
  19. package/dist/adaptors/dao3/server.mjs +2 -0
  20. package/dist/adaptors/dao3/server.mjs.map +1 -0
  21. package/dist/adaptors/electron/constants.d.mts +5 -0
  22. package/dist/adaptors/electron/constants.d.ts +5 -0
  23. package/dist/adaptors/electron/constants.js +2 -0
  24. package/dist/adaptors/electron/constants.js.map +1 -0
  25. package/dist/adaptors/electron/constants.mjs +2 -0
  26. package/dist/adaptors/electron/constants.mjs.map +1 -0
  27. package/dist/adaptors/electron/main.d.mts +10 -0
  28. package/dist/adaptors/electron/main.d.ts +10 -0
  29. package/dist/adaptors/electron/main.js +2 -0
  30. package/dist/adaptors/electron/main.js.map +1 -0
  31. package/dist/adaptors/electron/main.mjs +2 -0
  32. package/dist/adaptors/electron/main.mjs.map +1 -0
  33. package/dist/adaptors/electron/messenger.d.mts +8 -0
  34. package/dist/adaptors/electron/messenger.d.ts +8 -0
  35. package/dist/adaptors/electron/messenger.js +2 -0
  36. package/dist/adaptors/electron/messenger.js.map +1 -0
  37. package/dist/adaptors/electron/messenger.mjs +2 -0
  38. package/dist/adaptors/electron/messenger.mjs.map +1 -0
  39. package/dist/adaptors/electron/preload.d.mts +6 -0
  40. package/dist/adaptors/electron/preload.d.ts +6 -0
  41. package/dist/adaptors/electron/preload.js +2 -0
  42. package/dist/adaptors/electron/preload.js.map +1 -0
  43. package/dist/adaptors/electron/preload.mjs +2 -0
  44. package/dist/adaptors/electron/preload.mjs.map +1 -0
  45. package/dist/adaptors/electron/renderer.d.mts +9 -0
  46. package/dist/adaptors/electron/renderer.d.ts +9 -0
  47. package/dist/adaptors/electron/renderer.js +2 -0
  48. package/dist/adaptors/electron/renderer.js.map +1 -0
  49. package/dist/adaptors/electron/renderer.mjs +2 -0
  50. package/dist/adaptors/electron/renderer.mjs.map +1 -0
  51. package/dist/adaptors/http.d.mts +15 -0
  52. package/dist/adaptors/http.d.ts +6 -4
  53. package/dist/adaptors/http.js +1 -26
  54. package/dist/adaptors/http.js.map +1 -1
  55. package/dist/adaptors/http.mjs +2 -0
  56. package/dist/adaptors/http.mjs.map +1 -0
  57. package/dist/adaptors/iframe.d.mts +7 -0
  58. package/dist/adaptors/iframe.d.ts +5 -2
  59. package/dist/adaptors/iframe.js +1 -38
  60. package/dist/adaptors/iframe.js.map +1 -1
  61. package/dist/adaptors/iframe.mjs +2 -0
  62. package/dist/adaptors/iframe.mjs.map +1 -0
  63. package/dist/index.d.mts +16 -0
  64. package/dist/index.d.ts +16 -10
  65. package/dist/index.js +1 -9
  66. package/dist/index.js.map +1 -1
  67. package/dist/index.mjs +2 -0
  68. package/dist/index.mjs.map +1 -0
  69. package/dist/remote.d.mts +81 -0
  70. package/dist/remote.d.ts +6 -4
  71. package/dist/remote.js +1 -196
  72. package/dist/remote.js.map +1 -1
  73. package/dist/remote.mjs +2 -0
  74. package/dist/remote.mjs.map +1 -0
  75. package/dist/remoteValue/exposeToRemote.d.mts +43 -0
  76. package/dist/remoteValue/exposeToRemote.d.ts +7 -5
  77. package/dist/remoteValue/exposeToRemote.js +1 -52
  78. package/dist/remoteValue/exposeToRemote.js.map +1 -1
  79. package/dist/remoteValue/exposeToRemote.mjs +2 -0
  80. package/dist/remoteValue/exposeToRemote.mjs.map +1 -0
  81. package/dist/remoteValue/remoteValue.d.mts +29 -0
  82. package/dist/remoteValue/remoteValue.d.ts +6 -4
  83. package/dist/remoteValue/remoteValue.js +1 -67
  84. package/dist/remoteValue/remoteValue.js.map +1 -1
  85. package/dist/remoteValue/remoteValue.mjs +2 -0
  86. package/dist/remoteValue/remoteValue.mjs.map +1 -0
  87. package/dist/remoteValue/type.d.mts +67 -0
  88. package/dist/remoteValue/type.d.ts +20 -19
  89. package/dist/remoteValue/type.js +1 -1
  90. package/dist/remoteValue/type.js.map +1 -1
  91. package/dist/remoteValue/type.mjs +1 -0
  92. package/dist/remoteValue/type.mjs.map +1 -0
  93. package/dist/response.d.mts +105 -0
  94. package/dist/response.d.ts +6 -5
  95. package/dist/response.js +1 -154
  96. package/dist/response.js.map +1 -1
  97. package/dist/response.mjs +2 -0
  98. package/dist/response.mjs.map +1 -0
  99. package/package.json +31 -24
  100. package/src/adaptor.ts +34 -34
  101. package/src/adaptors/dao3/client.ts +53 -53
  102. package/src/adaptors/dao3/server.ts +136 -136
  103. package/src/adaptors/electron/constants.ts +3 -0
  104. package/src/adaptors/electron/main.ts +59 -0
  105. package/src/adaptors/electron/messenger.ts +13 -0
  106. package/src/adaptors/electron/preload.ts +21 -0
  107. package/src/adaptors/electron/renderer.ts +52 -0
  108. package/src/adaptors/http.ts +31 -31
  109. package/src/adaptors/iframe.ts +47 -47
  110. package/src/index.ts +17 -12
  111. package/src/remote.ts +263 -260
  112. package/src/remoteValue/exposeToRemote.ts +102 -102
  113. package/src/remoteValue/remoteValue.ts +94 -94
  114. package/src/remoteValue/type.ts +124 -124
  115. package/src/response.ts +170 -170
@@ -1,102 +1,102 @@
1
- import { Adaptor, AdaptorPackageData } from '../adaptor'
2
- import { RemoteError, response } from '../response'
3
- import { RemoteCallData } from './type'
4
-
5
- type AdaptorData = AdaptorPackageData<RemoteCallData>
6
-
7
- interface ExposeProps {
8
- globalName: string
9
- adaptor: Adaptor
10
- /**
11
- * ['*'] or ['device_id_1', 'device_id_2']
12
- */
13
- exposeTo: string[]
14
- /**
15
- * 你可以在该回调中抛错,以阻止远程调用,
16
- * 也可以修改传入的 data
17
- */
18
- onRequest?: (e: AdaptorData) => RemoteCallData | Promise<RemoteCallData>
19
- /**
20
- * 如果你想要自定义处理函数,
21
- * 需要谨慎且完善地处理各种 paths, args,
22
- * 以避免远程调用时出现未预期的错误。
23
- *
24
- * ---
25
- *
26
- * 我的默认处理程序谨供参考:
27
- * ``` ts
28
- * let target = obj
29
- * for (let i = 0; i < data.paths.length; i += 1) {
30
- * target = target[data.paths[i] as keyof typeof target] as typeof target
31
- * }
32
- * if (target instanceof Function) {
33
- * return target(...data.args)
34
- * }
35
- * return target
36
- * ```
37
- *
38
- * @returns 返回值将会被发送给远程调用方,可以是立即数,也可以是 Promise(Promise 会 await 后再返回)
39
- */
40
- handler?: (e: AdaptorData) => unknown
41
- }
42
-
43
- function defaultOnRequest(e: AdaptorData) {
44
- return e.data
45
- }
46
-
47
- const geneDefaultHandler: <T>(obj: T) => (data: AdaptorData) => unknown =
48
- (obj) =>
49
- ({ data }) => {
50
- let target = obj
51
- for (let i = 0; i < data.paths.length; i += 1) {
52
- target = target[data.paths[i] as keyof typeof target] as typeof target
53
- }
54
- if (target instanceof Function) {
55
- return target(...data.args)
56
- }
57
- return target
58
- }
59
-
60
- export function isRemoteValueEvent(eventName: string) {
61
- return eventName.startsWith('__REMOTE_VALUE_REQ__')
62
- }
63
-
64
- export function exposeToRemote<T extends object>(obj: T, options: ExposeProps) {
65
- const {
66
- globalName,
67
- adaptor,
68
- exposeTo,
69
- handler: inputHandler,
70
- onRequest = defaultOnRequest,
71
- } = options
72
- const callback = async (e: AdaptorPackageData) => {
73
- try {
74
- const data = await onRequest(e as AdaptorData)
75
- if (!exposeTo.includes(e.deviceId) && !exposeTo.includes('*')) {
76
- throw new RemoteError('permission denied')
77
- }
78
- const handler = inputHandler ?? geneDefaultHandler(obj)
79
- const res = await handler({
80
- ...e,
81
- data,
82
- })
83
- adaptor.emit({
84
- name: e.callbackName ?? 'IMPOSSIBLE_NO_CALLBACK_NAME',
85
- deviceId: e.targetDeviceId,
86
- targetDeviceId: e.deviceId,
87
- data: response.success(res),
88
- })
89
- } catch (error) {
90
- adaptor.emit({
91
- name: e.callbackName ?? 'IMPOSSIBLE_NO_CALLBACK_NAME',
92
- deviceId: e.targetDeviceId,
93
- targetDeviceId: e.deviceId,
94
- data: response.error(RemoteError.fromError(error)),
95
- })
96
- }
97
- }
98
- adaptor.on(`__REMOTE_VALUE_REQ__${globalName}`, callback)
99
- return () => {
100
- adaptor.off(`__REMOTE_VALUE_REQ__${globalName}`, callback)
101
- }
102
- }
1
+ import { Adaptor, AdaptorPackageData } from '../adaptor'
2
+ import { RemoteError, response } from '../response'
3
+ import { RemoteCallData } from './type'
4
+
5
+ type AdaptorData = AdaptorPackageData<RemoteCallData>
6
+
7
+ interface ExposeProps {
8
+ globalName: string
9
+ adaptor: Adaptor
10
+ /**
11
+ * ['*'] or ['device_id_1', 'device_id_2']
12
+ */
13
+ exposeTo: string[]
14
+ /**
15
+ * 你可以在该回调中抛错,以阻止远程调用,
16
+ * 也可以修改传入的 data
17
+ */
18
+ onRequest?: (e: AdaptorData) => RemoteCallData | Promise<RemoteCallData>
19
+ /**
20
+ * 如果你想要自定义处理函数,
21
+ * 需要谨慎且完善地处理各种 paths, args,
22
+ * 以避免远程调用时出现未预期的错误。
23
+ *
24
+ * ---
25
+ *
26
+ * 我的默认处理程序谨供参考:
27
+ * ``` ts
28
+ * let target = obj
29
+ * for (let i = 0; i < data.paths.length; i += 1) {
30
+ * target = target[data.paths[i] as keyof typeof target] as typeof target
31
+ * }
32
+ * if (target instanceof Function) {
33
+ * return target(...data.args)
34
+ * }
35
+ * return target
36
+ * ```
37
+ *
38
+ * @returns 返回值将会被发送给远程调用方,可以是立即数,也可以是 Promise(Promise 会 await 后再返回)
39
+ */
40
+ handler?: (e: AdaptorData) => unknown
41
+ }
42
+
43
+ function defaultOnRequest(e: AdaptorData) {
44
+ return e.data
45
+ }
46
+
47
+ const geneDefaultHandler: <T>(obj: T) => (data: AdaptorData) => unknown =
48
+ (obj) =>
49
+ ({ data }) => {
50
+ let target = obj
51
+ for (let i = 0; i < data.paths.length; i += 1) {
52
+ target = target[data.paths[i] as keyof typeof target] as typeof target
53
+ }
54
+ if (target instanceof Function) {
55
+ return target(...data.args)
56
+ }
57
+ return target
58
+ }
59
+
60
+ export function isRemoteValueEvent(eventName: string) {
61
+ return eventName.startsWith('__REMOTE_VALUE_REQ__')
62
+ }
63
+
64
+ export function exposeToRemote<T extends object>(obj: T, options: ExposeProps) {
65
+ const {
66
+ globalName,
67
+ adaptor,
68
+ exposeTo,
69
+ handler: inputHandler,
70
+ onRequest = defaultOnRequest,
71
+ } = options
72
+ const callback = async (e: AdaptorPackageData) => {
73
+ try {
74
+ const data = await onRequest(e as AdaptorData)
75
+ if (!exposeTo.includes(e.deviceId) && !exposeTo.includes('*')) {
76
+ throw new RemoteError('permission denied')
77
+ }
78
+ const handler = inputHandler ?? geneDefaultHandler(obj)
79
+ const res = await handler({
80
+ ...e,
81
+ data,
82
+ })
83
+ adaptor.emit({
84
+ name: e.callbackName ?? 'IMPOSSIBLE_NO_CALLBACK_NAME',
85
+ deviceId: e.targetDeviceId,
86
+ targetDeviceId: e.deviceId,
87
+ data: response.success(res),
88
+ })
89
+ } catch (error) {
90
+ adaptor.emit({
91
+ name: e.callbackName ?? 'IMPOSSIBLE_NO_CALLBACK_NAME',
92
+ deviceId: e.targetDeviceId,
93
+ targetDeviceId: e.deviceId,
94
+ data: response.error(RemoteError.fromError(error)),
95
+ })
96
+ }
97
+ }
98
+ adaptor.on(`__REMOTE_VALUE_REQ__${globalName}`, callback)
99
+ return () => {
100
+ adaptor.off(`__REMOTE_VALUE_REQ__${globalName}`, callback)
101
+ }
102
+ }
@@ -1,94 +1,94 @@
1
- import { RemoteError, RemoteTimeoutError, response } from '../response'
2
- import { Adaptor, AdaptorCallback, AdaptorPackageData } from '../adaptor'
3
- import type { RemoteCallData, ToFunc } from './type'
4
-
5
- function noop() {
6
- // pass
7
- }
8
-
9
- type RemoteValueProps = Pick<
10
- AdaptorPackageData,
11
- 'deviceId' | 'targetDeviceId'
12
- > & {
13
- globalName: string
14
- adaptor: Adaptor
15
- timeoutMs?: number
16
- log?: boolean
17
- }
18
-
19
- function geneProxy<T extends object>(paths: string[], props: RemoteValueProps) {
20
- return new Proxy<ToFunc<T>>(noop as unknown as ToFunc<T>, {
21
- apply(target, thisArg, argArray) {
22
- const {
23
- adaptor,
24
- globalName,
25
- timeoutMs = 30000,
26
- log = false,
27
- ...restProps
28
- } = props
29
- const randomStr = Math.random().toString(36).slice(2)
30
- const name = `__REMOTE_VALUE_REQ__${globalName}`
31
- const responseName = `__REMOTE_VALUE_RES__${[globalName, ...paths].join('.')}-${randomStr}`
32
-
33
- if (log) {
34
- console.log(
35
- `[remoteValue] [${restProps.deviceId}] 正在访问远端 [${restProps.targetDeviceId}] 的变量: "${[globalName, ...paths].join('.')}"`
36
- )
37
- }
38
-
39
- return new Promise((resolve, reject) => {
40
- let timer: NodeJS.Timeout | undefined
41
- const callback: AdaptorCallback = (e) => {
42
- clearTimeout(timer)
43
- if (RemoteError.isRemoteError(e.data)) {
44
- reject(RemoteError.fromError(e.data))
45
- } else {
46
- resolve((e.data as ReturnType<typeof response.success>)?.data)
47
- }
48
- }
49
- adaptor.once(responseName, callback)
50
- timer = setTimeout(() => {
51
- adaptor.off(responseName, callback)
52
- reject(
53
- new RemoteTimeoutError(
54
- `timeout: ${[globalName, ...paths].join('.')}`
55
- )
56
- )
57
- }, timeoutMs)
58
- adaptor.emit({
59
- name,
60
- callbackName: responseName,
61
- ...restProps,
62
- data: {
63
- paths,
64
- args: argArray,
65
- } satisfies RemoteCallData,
66
- })
67
- })
68
- },
69
- get(target, prop) {
70
- return geneProxy([...paths, prop as string], props)
71
- },
72
- })
73
- }
74
-
75
- /**
76
- * @example
77
- * ```
78
- * const obj = remoteValue<{
79
- * a: number;
80
- * b: {
81
- * c: string;
82
- * };
83
- * funcD: () => number
84
- * }>()
85
- *
86
- * const val_1 = await obj.a() // number
87
- * const val_2 = await obj.b() // { c: string }
88
- * const val_3 = await obj.b.c() // string
89
- * const val_4 = await obj.funcD() // number
90
- * ```
91
- */
92
- export function remoteValue<T extends object>(props: RemoteValueProps) {
93
- return geneProxy<T>([], props)
94
- }
1
+ import { RemoteError, RemoteTimeoutError, response } from '../response'
2
+ import { Adaptor, AdaptorCallback, AdaptorPackageData } from '../adaptor'
3
+ import type { RemoteCallData, ToFunc } from './type'
4
+
5
+ function noop() {
6
+ // pass
7
+ }
8
+
9
+ type RemoteValueProps = Pick<
10
+ AdaptorPackageData,
11
+ 'deviceId' | 'targetDeviceId'
12
+ > & {
13
+ globalName: string
14
+ adaptor: Adaptor
15
+ timeoutMs?: number
16
+ log?: boolean
17
+ }
18
+
19
+ function geneProxy<T extends object>(paths: string[], props: RemoteValueProps) {
20
+ return new Proxy<ToFunc<T>>(noop as unknown as ToFunc<T>, {
21
+ apply(target, thisArg, argArray) {
22
+ const {
23
+ adaptor,
24
+ globalName,
25
+ timeoutMs = 30000,
26
+ log = false,
27
+ ...restProps
28
+ } = props
29
+ const randomStr = Math.random().toString(36).slice(2)
30
+ const name = `__REMOTE_VALUE_REQ__${globalName}`
31
+ const responseName = `__REMOTE_VALUE_RES__${[globalName, ...paths].join('.')}-${randomStr}`
32
+
33
+ if (log) {
34
+ console.log(
35
+ `[remoteValue] [${restProps.deviceId}] 正在访问远端 [${restProps.targetDeviceId}] 的变量: "${[globalName, ...paths].join('.')}"`
36
+ )
37
+ }
38
+
39
+ return new Promise((resolve, reject) => {
40
+ let timer: NodeJS.Timeout | undefined
41
+ const callback: AdaptorCallback = (e) => {
42
+ clearTimeout(timer)
43
+ if (RemoteError.isRemoteError(e.data)) {
44
+ reject(RemoteError.fromError(e.data))
45
+ } else {
46
+ resolve((e.data as ReturnType<typeof response.success>)?.data)
47
+ }
48
+ }
49
+ adaptor.once(responseName, callback)
50
+ timer = setTimeout(() => {
51
+ adaptor.off(responseName, callback)
52
+ reject(
53
+ new RemoteTimeoutError(
54
+ `timeout: ${[globalName, ...paths].join('.')}`
55
+ )
56
+ )
57
+ }, timeoutMs)
58
+ adaptor.emit({
59
+ name,
60
+ callbackName: responseName,
61
+ ...restProps,
62
+ data: {
63
+ paths,
64
+ args: argArray,
65
+ } satisfies RemoteCallData,
66
+ })
67
+ })
68
+ },
69
+ get(target, prop) {
70
+ return geneProxy([...paths, prop as string], props)
71
+ },
72
+ })
73
+ }
74
+
75
+ /**
76
+ * @example
77
+ * ```
78
+ * const obj = remoteValue<{
79
+ * a: number;
80
+ * b: {
81
+ * c: string;
82
+ * };
83
+ * funcD: () => number
84
+ * }>()
85
+ *
86
+ * const val_1 = await obj.a() // number
87
+ * const val_2 = await obj.b() // { c: string }
88
+ * const val_3 = await obj.b.c() // string
89
+ * const val_4 = await obj.funcD() // number
90
+ * ```
91
+ */
92
+ export function remoteValue<T extends object>(props: RemoteValueProps) {
93
+ return geneProxy<T>([], props)
94
+ }
@@ -1,124 +1,124 @@
1
- type HasFunc<T> = T extends (...args: unknown[]) => unknown
2
- ? true
3
- : T extends unknown[]
4
- ? { [K in keyof T]: HasFunc<T[K]> }[number] extends false
5
- ? false
6
- : true
7
- : T extends object
8
- ? { [K in keyof T]: HasFunc<T[K]> }[keyof T] extends false
9
- ? false
10
- : true
11
- : false
12
-
13
- export type ToFunc<T extends object> = {
14
- [K in keyof T]: T[K] extends (...args: infer Args) => infer Ret
15
- ? (...args: Args) => Promise<Awaited<Ret>>
16
- : HasFunc<T[K]> extends false
17
- ? () => Promise<T[K]>
18
- : T[K] extends object
19
- ? ToFunc<T[K]>
20
- : never
21
- }
22
-
23
- export interface RemoteCallData {
24
- paths: string[]
25
- args: unknown[]
26
- }
27
-
28
- // 下面的都是测试代码,用于测试 ToFunc
29
-
30
- type Assert<T extends true> = T
31
-
32
- interface TestObj {
33
- a1: number
34
- a2: number[]
35
- a3: [number, string]
36
- a4: {
37
- b: number
38
- c: [string]
39
- }
40
- a5: () => Promise<number>
41
- a6: () => Promise<number[]>
42
- a7: () => Promise<[number, string]>
43
- b: {
44
- b1: number
45
- b2: number[]
46
- b3: [number, string]
47
- b4: () => {
48
- b: number
49
- c: [string]
50
- }
51
- b5: () => Promise<number>
52
- b6: () => Promise<number[]>
53
- b7: () => Promise<[number, string]>
54
- }
55
- f: {
56
- b: number
57
- c: {
58
- d: () => number
59
- }
60
- }
61
- }
62
-
63
- export type TestA1 = Assert<
64
- ToFunc<TestObj>['a1'] extends () => Promise<number> ? true : false
65
- >
66
- export type TestA2 = Assert<
67
- ToFunc<TestObj>['a2'] extends () => Promise<number[]> ? true : false
68
- >
69
- export type TestA3 = Assert<
70
- ToFunc<TestObj>['a3'] extends () => Promise<[number, string]> ? true : false
71
- >
72
- export type TestA4 = Assert<
73
- ToFunc<TestObj>['a4'] extends () => Promise<{
74
- b: number
75
- c: [string]
76
- }>
77
- ? true
78
- : false
79
- >
80
- export type TestA5 = Assert<
81
- ToFunc<TestObj>['a5'] extends () => Promise<number> ? true : false
82
- >
83
- export type TestA6 = Assert<
84
- ToFunc<TestObj>['a6'] extends () => Promise<number[]> ? true : false
85
- >
86
- export type TestA7 = Assert<
87
- ToFunc<TestObj>['a7'] extends () => Promise<[number, string]> ? true : false
88
- >
89
- export type TestB1 = Assert<
90
- ToFunc<TestObj>['b']['b1'] extends () => Promise<number> ? true : false
91
- >
92
- export type TestB2 = Assert<
93
- ToFunc<TestObj>['b']['b2'] extends () => Promise<number[]> ? true : false
94
- >
95
- export type TestB3 = Assert<
96
- ToFunc<TestObj>['b']['b3'] extends () => Promise<[number, string]>
97
- ? true
98
- : false
99
- >
100
- export type TestB4 = Assert<
101
- ToFunc<TestObj>['b']['b4'] extends () => Promise<{
102
- b: number
103
- c: [string]
104
- }>
105
- ? true
106
- : false
107
- >
108
- export type TestB5 = Assert<
109
- ToFunc<TestObj>['b']['b5'] extends () => Promise<number> ? true : false
110
- >
111
- export type TestB6 = Assert<
112
- ToFunc<TestObj>['b']['b6'] extends () => Promise<number[]> ? true : false
113
- >
114
- export type TestB7 = Assert<
115
- ToFunc<TestObj>['b']['b7'] extends () => Promise<[number, string]>
116
- ? true
117
- : false
118
- >
119
- export type TestF = Assert<
120
- ToFunc<TestObj>['f']['b'] extends () => Promise<number> ? true : false
121
- >
122
- export type TestF2 = Assert<
123
- ToFunc<TestObj>['f']['c']['d'] extends () => Promise<number> ? true : false
124
- >
1
+ type HasFunc<T> = T extends (...args: unknown[]) => unknown
2
+ ? true
3
+ : T extends unknown[]
4
+ ? { [K in keyof T]: HasFunc<T[K]> }[number] extends false
5
+ ? false
6
+ : true
7
+ : T extends object
8
+ ? { [K in keyof T]: HasFunc<T[K]> }[keyof T] extends false
9
+ ? false
10
+ : true
11
+ : false
12
+
13
+ export type ToFunc<T extends object> = {
14
+ [K in keyof T]: T[K] extends (...args: infer Args) => infer Ret
15
+ ? (...args: Args) => Promise<Awaited<Ret>>
16
+ : HasFunc<T[K]> extends false
17
+ ? () => Promise<T[K]>
18
+ : T[K] extends object
19
+ ? ToFunc<T[K]>
20
+ : never
21
+ }
22
+
23
+ export interface RemoteCallData {
24
+ paths: string[]
25
+ args: unknown[]
26
+ }
27
+
28
+ // 下面的都是测试代码,用于测试 ToFunc
29
+
30
+ type Assert<T extends true> = T
31
+
32
+ interface TestObj {
33
+ a1: number
34
+ a2: number[]
35
+ a3: [number, string]
36
+ a4: {
37
+ b: number
38
+ c: [string]
39
+ }
40
+ a5: () => Promise<number>
41
+ a6: () => Promise<number[]>
42
+ a7: () => Promise<[number, string]>
43
+ b: {
44
+ b1: number
45
+ b2: number[]
46
+ b3: [number, string]
47
+ b4: () => {
48
+ b: number
49
+ c: [string]
50
+ }
51
+ b5: () => Promise<number>
52
+ b6: () => Promise<number[]>
53
+ b7: () => Promise<[number, string]>
54
+ }
55
+ f: {
56
+ b: number
57
+ c: {
58
+ d: () => number
59
+ }
60
+ }
61
+ }
62
+
63
+ export type TestA1 = Assert<
64
+ ToFunc<TestObj>['a1'] extends () => Promise<number> ? true : false
65
+ >
66
+ export type TestA2 = Assert<
67
+ ToFunc<TestObj>['a2'] extends () => Promise<number[]> ? true : false
68
+ >
69
+ export type TestA3 = Assert<
70
+ ToFunc<TestObj>['a3'] extends () => Promise<[number, string]> ? true : false
71
+ >
72
+ export type TestA4 = Assert<
73
+ ToFunc<TestObj>['a4'] extends () => Promise<{
74
+ b: number
75
+ c: [string]
76
+ }>
77
+ ? true
78
+ : false
79
+ >
80
+ export type TestA5 = Assert<
81
+ ToFunc<TestObj>['a5'] extends () => Promise<number> ? true : false
82
+ >
83
+ export type TestA6 = Assert<
84
+ ToFunc<TestObj>['a6'] extends () => Promise<number[]> ? true : false
85
+ >
86
+ export type TestA7 = Assert<
87
+ ToFunc<TestObj>['a7'] extends () => Promise<[number, string]> ? true : false
88
+ >
89
+ export type TestB1 = Assert<
90
+ ToFunc<TestObj>['b']['b1'] extends () => Promise<number> ? true : false
91
+ >
92
+ export type TestB2 = Assert<
93
+ ToFunc<TestObj>['b']['b2'] extends () => Promise<number[]> ? true : false
94
+ >
95
+ export type TestB3 = Assert<
96
+ ToFunc<TestObj>['b']['b3'] extends () => Promise<[number, string]>
97
+ ? true
98
+ : false
99
+ >
100
+ export type TestB4 = Assert<
101
+ ToFunc<TestObj>['b']['b4'] extends () => Promise<{
102
+ b: number
103
+ c: [string]
104
+ }>
105
+ ? true
106
+ : false
107
+ >
108
+ export type TestB5 = Assert<
109
+ ToFunc<TestObj>['b']['b5'] extends () => Promise<number> ? true : false
110
+ >
111
+ export type TestB6 = Assert<
112
+ ToFunc<TestObj>['b']['b6'] extends () => Promise<number[]> ? true : false
113
+ >
114
+ export type TestB7 = Assert<
115
+ ToFunc<TestObj>['b']['b7'] extends () => Promise<[number, string]>
116
+ ? true
117
+ : false
118
+ >
119
+ export type TestF = Assert<
120
+ ToFunc<TestObj>['f']['b'] extends () => Promise<number> ? true : false
121
+ >
122
+ export type TestF2 = Assert<
123
+ ToFunc<TestObj>['f']['c']['d'] extends () => Promise<number> ? true : false
124
+ >