Skip to content

Commit de856f6

Browse files
committed
feat: 新增加通配符事件类型推断
1 parent fa4a8d2 commit de856f6

8 files changed

Lines changed: 1326 additions & 974 deletions

File tree

.changeset/five-coats-sniff.md

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,21 @@
22
'fastevent': patch
33
---
44

5-
新增加通配符事件类型推断
5+
[feat] 新增加通配符事件类型推断
6+
7+
```ts
8+
import { FastEvent } from 'fastevent';
9+
type Events = {
10+
'users/*/online': string;
11+
'users/*/offline': string;
12+
};
13+
const emitter = new FastEvent<Events>();
14+
15+
// 按通配符匹配事件类型
16+
emitter.emit('users/123/online', '123'); //
17+
emitter.emit('users/123/online', 1); //
18+
emitter.on('users/123/online', ({ type, payload }) => {
19+
// type的类型 === 'users/*/online'
20+
// payload的类型 === string
21+
});
22+
```
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
/* eslint-disable no-unused-vars */
2+
import { describe, test, expect } from 'vitest';
3+
import type { Equal, Expect, NotAny } from '@type-challenges/utils';
4+
import { MatchEventType, ScopeEvents } from '../../types';
5+
import { FastEvent } from '../../event';
6+
7+
describe('事件通配符匹配', () => {
8+
test('精确匹配', () => {
9+
type Events = {
10+
a: string;
11+
'b/b1': number;
12+
'c/c1/c2': boolean;
13+
};
14+
type cases = [
15+
Expect<Equal<MatchEventType<'a', Events>, { a: string }>>,
16+
Expect<Equal<MatchEventType<'b/b1', Events>, { 'b/b1': number }>>,
17+
Expect<Equal<MatchEventType<'c/c1/c2', Events>, { 'c/c1/c2': boolean }>>,
18+
];
19+
});
20+
test('不匹配的情况', () => {
21+
type Events = {
22+
'a/*': string;
23+
'b/b1': number;
24+
'c/c1/c2': boolean;
25+
};
26+
27+
type cases = [Expect<Equal<MatchEventType<'a', Events>, { a: any }>>];
28+
});
29+
test('单层通配符匹配', () => {
30+
type Events = {
31+
'a/*': string;
32+
'a/*/x': string;
33+
'b/*': number;
34+
'b/*/y': number;
35+
'c/*': boolean;
36+
};
37+
type cases = [
38+
Expect<Equal<MatchEventType<'a', Events>, { a: any }>>,
39+
Expect<Equal<MatchEventType<'a/x', Events>, { 'a/*': string }>>,
40+
Expect<Equal<MatchEventType<'a/y', Events>, { 'a/*': string }>>,
41+
Expect<Equal<MatchEventType<'a/z/x', Events>, { 'a/*/x': string }>>,
42+
43+
Expect<Equal<MatchEventType<'b', Events>, { b: any }>>,
44+
Expect<Equal<MatchEventType<'b/x', Events>, { 'b/*': number }>>,
45+
Expect<Equal<MatchEventType<'b/y', Events>, { 'b/*': number }>>,
46+
Expect<Equal<MatchEventType<'b/z/y', Events>, { 'b/*/y': number }>>,
47+
];
48+
});
49+
test('多个通配符匹配', () => {
50+
type Events = {
51+
'a/*': 1;
52+
'a/*/x': 2;
53+
'a/*/*/x': 2;
54+
'a/*/x/*/x': 3;
55+
'a/*/x/*/x/*/x': 4;
56+
};
57+
type cases = [
58+
Expect<Equal<MatchEventType<'a', Events>, { a: any }>>,
59+
Expect<Equal<MatchEventType<'a/1', Events>, { 'a/*': 1 }>>,
60+
Expect<Equal<MatchEventType<'a/1/x', Events>, { 'a/*/x': 2 }>>,
61+
Expect<Equal<MatchEventType<'a/1/2/x', Events>, { 'a/*/*/x': 2 }>>,
62+
Expect<Equal<MatchEventType<'a/1/x/2/x', Events>, { 'a/*/x/*/x': 3 }>>,
63+
Expect<Equal<MatchEventType<'a/1/x/2/x/3/x', Events>, { 'a/*/x/*/x/*/x': 4 }>>,
64+
];
65+
});
66+
test('未尾通配符匹配', () => {
67+
type Events = {
68+
'a/*': 1;
69+
'a/*/*': 2;
70+
'a/*/*/*': 3;
71+
'a/*/*/*/*': 4;
72+
'a/*/*/*/*/*': 5;
73+
'a/*/*/*/*/*/*': 6;
74+
};
75+
type cases = [
76+
Expect<Equal<MatchEventType<'a', Events>, { a: any }>>,
77+
Expect<Equal<MatchEventType<'a/1', Events>, { 'a/*': 1 }>>,
78+
Expect<Equal<MatchEventType<'a/1/2', Events>, { 'a/*/*': 2 }>>,
79+
Expect<Equal<MatchEventType<'a/1/2/3', Events>, { 'a/*/*/*': 3 }>>,
80+
Expect<Equal<MatchEventType<'a/1/2/3/4', Events>, { 'a/*/*/*/*': 4 }>>,
81+
Expect<Equal<MatchEventType<'a/1/2/3/4/5', Events>, { 'a/*/*/*/*/*': 5 }>>,
82+
Expect<Equal<MatchEventType<'a/1/2/3/4/5/6', Events>, { 'a/*/*/*/*/*/*': 6 }>>,
83+
];
84+
});
85+
test('多级通配符匹配', () => {
86+
type Events = {
87+
'a/*': 1;
88+
'a/b/**': 2;
89+
'a/b/c1/**': 3;
90+
'a/b/c2/**': 3;
91+
'a/b/c/d/**': 4;
92+
'a/b/c/d/e/**': 5;
93+
};
94+
95+
type s = MatchEventType<'a/b/c1/x', Events>;
96+
97+
type cases = [
98+
Expect<Equal<MatchEventType<'a', Events>, { a: any }>>,
99+
Expect<Equal<MatchEventType<'a/x', Events>, { 'a/*': 1 }>>,
100+
Expect<Equal<MatchEventType<'a/b/x', Events>, { 'a/b/**': 2 }>>,
101+
Expect<Equal<MatchEventType<'a/b/x/y', Events>, { 'a/b/**': 2 }>>,
102+
Expect<Equal<MatchEventType<'a/b/x/y/z', Events>, { 'a/b/**': 2 }>>,
103+
];
104+
});
105+
test('订阅通配符事件', () => {
106+
type Events = {
107+
'users/*/online': string;
108+
'users/*/offline': boolean;
109+
'post/*': number;
110+
};
111+
const emitter = new FastEvent<Events>();
112+
emitter.on('users/fisher/online', (event) => {
113+
type cases = [Expect<Equal<typeof event.type, 'users/*/online'>>, Expect<Equal<typeof event.payload, string>>];
114+
});
115+
emitter.on('users/fisher/offline', (event) => {
116+
type cases = [Expect<Equal<typeof event.type, 'users/*/offline'>>, Expect<Equal<typeof event.payload, boolean>>];
117+
});
118+
emitter.on('users/xxxxx', (event) => {
119+
type cases = [Expect<Equal<typeof event.type, 'users/xxxxx'>>, Expect<Equal<typeof event.payload, any>>];
120+
});
121+
emitter.once('users/fisher/online', (event) => {
122+
type cases = [Expect<Equal<typeof event.type, 'users/*/online'>>, Expect<Equal<typeof event.payload, string>>];
123+
});
124+
emitter.once('users/fisher/offline', (event) => {
125+
type cases = [Expect<Equal<typeof event.type, 'users/*/offline'>>, Expect<Equal<typeof event.payload, boolean>>];
126+
});
127+
emitter.once('users/xxxxx', (event) => {
128+
type cases = [Expect<Equal<typeof event.type, 'users/xxxxx'>>, Expect<Equal<typeof event.payload, any>>];
129+
});
130+
});
131+
test('发布通配符事件', () => {
132+
type Events = {
133+
a: number;
134+
'users/*/online': { name: string; status?: number };
135+
'users/*/offline': boolean;
136+
'posts/**': number;
137+
};
138+
const emitter = new FastEvent<Events>();
139+
emitter.emit('a', 1);
140+
emitter.emit('users/fisher/online', { name: 'string', status: 1 });
141+
emitter.emit('users/fisher/online', { name: 'string' });
142+
emitter.emit('users/fisher/offline', true);
143+
emitter.emit('posts/fisher/offline', 1);
144+
145+
// emitter.emit('users/fisher/online', 'x');
146+
// emitter.emit('users/fisher/offline', 1);
147+
// emitter.emit('posts/fisher/offline', true);
148+
});
149+
});

0 commit comments

Comments
 (0)