Skip to content

Commit 9d62122

Browse files
committed
chore: improve types
test: convert tests to ts
1 parent 8e2fed1 commit 9d62122

14 files changed

+139
-110
lines changed

Diff for: jest.config.js

+4-7
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,6 @@ module.exports = {
66

77
forceExit: false,
88

9-
// https://github.com/facebook/jest/pull/6747 fix warning here
10-
// But its performance overhead is pretty bad (30+%).
11-
// detectOpenHandles: true
12-
139
setupFilesAfterEnv: ['./test/utils/setup'],
1410

1511
coverageDirectory: './coverage',
@@ -31,16 +27,17 @@ module.exports = {
3127
],
3228

3329
transform: {
34-
'^.+\\.[tj]s$': 'babel-jest',
35-
'.*\\.(vue)$': 'vue-jest'
30+
'^.+\\.jsx?$': 'babel-jest',
31+
'^.+\\.tsx?$': 'ts-jest',
32+
'^.+\\.vue$': 'vue-jest'
3633
},
3734

3835
moduleFileExtensions: [
3936
'ts',
4037
'js',
4138
'json'
4239
],
43-
40+
4441
globals: {
4542
__DEV__: true,
4643
__BROWSER__: true,

Diff for: package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
"@rollup/plugin-commonjs": "^17.1.0",
6262
"@rollup/plugin-node-resolve": "^11.2.0",
6363
"@rollup/plugin-replace": "^2.4.1",
64+
"@types/jest": "^26.0.22",
6465
"@types/webpack": "^4.41.26",
6566
"@types/webpack-env": "^1.16.0",
6667
"@typescript-eslint/eslint-plugin": "^4.15.2",
@@ -100,7 +101,7 @@
100101
"selenium-webdriver": "^4.0.0-beta.1",
101102
"standard-version": "^9.1.1",
102103
"tib": "^0.7.5",
103-
"ts-jest": "^26.5.2",
104+
"ts-jest": "^26.5.4",
104105
"ts-loader": "^8.0.17",
105106
"typescript": "^4.2.2",
106107
"vite": "^2.0.4",

Diff for: src/manager.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,12 @@ export const createMetaManager = (config?: MetaConfig, resolver?: MetaResolver):
6060

6161
export class MetaManager {
6262
config: MetaConfig
63-
target: MergedObjectBuilder
63+
target: MergedObjectBuilder<MetaSource>
6464
resolver?: MetaResolverSetup
6565

6666
ssrCleanedUp: boolean = false
6767

68-
constructor (config: MetaConfig, target: MergedObjectBuilder, resolver: MetaResolver | ResolveMethod) {
68+
constructor (config: MetaConfig, target: MergedObjectBuilder<MetaSource>, resolver: MetaResolver | ResolveMethod) {
6969
this.config = config
7070
this.target = target
7171

@@ -83,7 +83,7 @@ export class MetaManager {
8383
return resolver.resolve(options, contexts, active, key, pathSegments)
8484
}
8585

86-
const mergedObject = createMergedObject(resolve, active)
86+
const mergedObject = createMergedObject<MetaSource>(resolve, active)
8787

8888
// TODO: validate resolver
8989
const manager = new MetaManager(config, mergedObject, resolver)

Diff for: src/object-merge/constants.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// https://github.com/microsoft/TypeScript/issues/1863
2-
export const IS_PROXY = Symbol('kIsProxy') as unknown as string
3-
export const PROXY_SOURCES = Symbol('kProxySources') as unknown as string
4-
export const PROXY_TARGET = Symbol('kProxyTarget') as unknown as string
5-
export const RESOLVE_CONTEXT = Symbol('kResolveContext') as unknown as string
2+
export const IS_PROXY = Symbol('kIsProxy')
3+
export const PROXY_SOURCES = Symbol('kProxySources')
4+
export const PROXY_TARGET = Symbol('kProxyTarget')
5+
export const RESOLVE_CONTEXT = Symbol('kResolveContext')

Diff for: src/object-merge/index.ts

+29-28
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
1-
import { PROXY_TARGET } from './constants'
1+
import { IS_PROXY, PROXY_SOURCES, PROXY_TARGET, RESOLVE_CONTEXT } from './constants'
22
import { createProxy } from './proxy'
33
import { recompute } from './recompute'
44

5-
export type MergeSource = {
6-
[key: string]: any
5+
export interface ResolveContext {}
6+
7+
export type MergeSource<T extends Object> = { [K in keyof T]: T[K] } & {
8+
[IS_PROXY]: boolean
9+
[PROXY_SOURCES]: MergeSource<T>[]
10+
[PROXY_TARGET]: MergeSource<T>
11+
[RESOLVE_CONTEXT]: ResolveContext
712
}
813

914
// eslint-disable-next-line no-use-before-define
@@ -15,49 +20,45 @@ export type MergedObject = {
1520

1621
export type PathSegments = Array<string>
1722

18-
export type ResolveContext = {}
19-
20-
export type ResolveMethod<T = ResolveContext> = (
21-
options: Array<any>,
22-
contexts: Array<T>,
23-
active: MergedObjectValue,
24-
key: string | number | symbol,
25-
pathSegments: PathSegments,
26-
) => MergedObjectValue
23+
export interface ResolveMethod<T = any, U = ResolveContext> {
24+
(
25+
options: Array<T>,
26+
contexts: Array<U>,
27+
active: MergedObjectValue,
28+
key: string | number | symbol,
29+
pathSegments: PathSegments,
30+
): MergedObjectValue
31+
}
2732

28-
export type MergeContext = {
33+
export type MergeContext<T> = {
2934
resolve: ResolveMethod
3035
active: MergedObject
31-
sources: Array<MergeSource>
36+
sources: MergeSource<T>[]
3237
}
3338

34-
export type MergedObjectBuilder = {
35-
context: MergeContext
39+
export type MergedObjectBuilder<T> = {
40+
context: MergeContext<T>
3641
compute: () => void
37-
addSource: (source: MergeSource, resolveContext: ResolveContext | undefined, recompute?: Boolean) => any
38-
delSource: (sourceOrProxy: MergeSource, recompute?: boolean) => boolean
42+
addSource: (source: T, resolveContext?: ResolveContext, recompute?: Boolean) => any
43+
delSource: (sourceOrProxy: T | MergeSource<T>, recompute?: boolean) => boolean
3944
}
4045

41-
export const createMergedObject = (resolve: ResolveMethod, active: MergedObject = {}): MergedObjectBuilder => {
42-
const sources: Array<MergeSource> = []
43-
44-
if (!active) {
45-
active = {}
46-
}
46+
export const createMergedObject = <T extends Object>(resolve: ResolveMethod<T>, active: T): MergedObjectBuilder<T> => {
47+
const sources: MergeSource<T>[] = []
4748

48-
const context: MergeContext = {
49+
const context: MergeContext<T> = {
4950
active,
5051
resolve,
5152
sources
5253
}
5354

54-
const compute: () => void = () => recompute(context)
55+
const compute: () => void = () => recompute<T>(context)
5556

5657
return {
5758
context,
5859
compute,
5960
addSource: (source, resolveContext, recompute = false) => {
60-
const proxy = createProxy(context, source, resolveContext || {})
61+
const proxy = createProxy<T>(context, source, resolveContext || {})
6162

6263
if (recompute) {
6364
compute()
@@ -66,7 +67,7 @@ export const createMergedObject = (resolve: ResolveMethod, active: MergedObject
6667
return proxy
6768
},
6869
delSource: (sourceOrProxy, recompute = true) => {
69-
const index = sources.findIndex(src => src === sourceOrProxy || src[PROXY_TARGET] === sourceOrProxy)
70+
const index = sources.findIndex(source => source === sourceOrProxy || source[PROXY_TARGET] === sourceOrProxy)
7071

7172
if (index > -1) {
7273
sources.splice(index, 1)

Diff for: src/object-merge/proxy.ts

+11-10
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ import { IS_PROXY, PROXY_SOURCES, PROXY_TARGET, RESOLVE_CONTEXT } from './consta
55
import { recompute } from './recompute'
66
import type { MergeContext, MergeSource, MergedObjectValue, PathSegments, ResolveContext } from '.'
77

8-
export const createProxy = (context: MergeContext, target: MergeSource, resolveContext: ResolveContext, pathSegments: PathSegments = []) => {
9-
const handler = createHandler(context, resolveContext, pathSegments)
10-
const proxy = markRaw(new Proxy(target, handler))
8+
export const createProxy = <T extends Record<string, any>>(context: MergeContext<T>, target: T, resolveContext: ResolveContext, pathSegments: PathSegments = []): MergeSource<T> => {
9+
const handler = createHandler<T>(context, resolveContext, pathSegments)
10+
const proxy = markRaw(new Proxy(target, handler)) as MergeSource<T>
1111

1212
if (!pathSegments.length && context.sources) {
1313
context.sources.push(proxy)
@@ -16,7 +16,7 @@ export const createProxy = (context: MergeContext, target: MergeSource, resolveC
1616
return proxy
1717
}
1818

19-
export const createHandler: (context: MergeContext, resolveContext: ResolveContext, pathSegments: PathSegments) => ProxyHandler<any> = (context, resolveContext, pathSegments = []) => ({
19+
export const createHandler = <T>(context: MergeContext<T>, resolveContext: ResolveContext, pathSegments: PathSegments = []): ProxyHandler<MergeSource<T>> => ({
2020
get: (target, key, receiver) => {
2121
if (key === IS_PROXY) {
2222
return true
@@ -40,11 +40,11 @@ export const createHandler: (context: MergeContext, resolveContext: ResolveConte
4040
return value
4141
}
4242

43-
if (!value[IS_PROXY]) {
43+
if (!(value as MergeSource<T>)[IS_PROXY]) {
4444
const keyPath: PathSegments = [...pathSegments, (key as string)]
4545

46-
value = createProxy(context, value, resolveContext, keyPath)
47-
target[key] = value
46+
value = createProxy<typeof value>(context, value, resolveContext, keyPath)
47+
Reflect.set(target, key, value)
4848
}
4949

5050
return value
@@ -87,8 +87,8 @@ export const createHandler: (context: MergeContext, resolveContext: ResolveConte
8787
return success
8888
}
8989

90-
let keyContexts: Array<ResolveContext> = []
91-
let keySources
90+
let keyContexts: ResolveContext[] = []
91+
let keySources: MergeSource<T>[]
9292

9393
if (isArrayItem) {
9494
keySources = proxies
@@ -138,6 +138,7 @@ export const createHandler: (context: MergeContext, resolveContext: ResolveConte
138138

139139
let index = 0
140140
for (const segment of pathSegments) {
141+
// @ts-ignore
141142
proxies = proxies.map(proxy => proxy[segment])
142143

143144
if (isArrayItem && index === pathSegments.length - 1) {
@@ -152,7 +153,7 @@ export const createHandler: (context: MergeContext, resolveContext: ResolveConte
152153
// Check if the key still exists in one of the sourceProxies,
153154
// if so resolve the new value, if not remove the key
154155
if (proxies.some(proxy => (key in proxy))) {
155-
let keyContexts: Array<ResolveContext> = []
156+
let keyContexts: ResolveContext[] = []
156157
let keySources
157158

158159
if (isArrayItem) {

Diff for: src/object-merge/recompute.ts

+5-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { clone, pluck } from '../utils'
33
import { RESOLVE_CONTEXT } from './constants'
44
import type { MergeContext, MergeSource, MergedObject, PathSegments, ResolveContext } from '.'
55

6-
export const allKeys = (source?: MergeSource, ...sources: Array<MergeSource>): Array<string> => {
6+
export const allKeys = <T>(source?: MergeSource<T>, ...sources: MergeSource<T>[]): string[] => {
77
const keys = source ? Object.keys(source) : []
88

99
if (sources) {
@@ -25,7 +25,7 @@ export const allKeys = (source?: MergeSource, ...sources: Array<MergeSource>): A
2525
return keys
2626
}
2727

28-
export const recompute = (context: MergeContext, sources?: Array<MergeSource>, target?: MergedObject, path: PathSegments = []): void => {
28+
export const recompute = <T>(context: MergeContext<T>, sources?: MergeSource<T>[], target?: MergedObject, path: PathSegments = []): void => {
2929
if (!path.length) {
3030
if (!target) {
3131
target = context.active
@@ -52,6 +52,7 @@ export const recompute = (context: MergeContext, sources?: Array<MergeSource>, t
5252

5353
for (const key of keys) {
5454
// This assumes consistent types usages for keys across sources
55+
// @ts-ignore
5556
if (isPlainObject(sources[0][key])) {
5657
if (!target[key]) {
5758
target[key] = {}
@@ -60,6 +61,7 @@ export const recompute = (context: MergeContext, sources?: Array<MergeSource>, t
6061
const keySources = []
6162
for (const source of sources) {
6263
if (key in source) {
64+
// @ts-ignore
6365
keySources.push(source[key])
6466
}
6567
}
@@ -69,6 +71,7 @@ export const recompute = (context: MergeContext, sources?: Array<MergeSource>, t
6971
}
7072

7173
// Ensure the target is an array if source is an array and target is empty
74+
// @ts-ignore
7275
if (!target[key] && isArray(sources[0][key])) {
7376
target[key] = []
7477
}

Diff for: src/resolvers/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ export interface ResolveOptionPredicament<T, U> {
44
(currentValue: T | undefined, context: U): T
55
}
66

7-
export const resolveOption = <T, U = ResolveContext>(predicament: ResolveOptionPredicament<T, U>, initialValue?: T): ResolveMethod<U> => (options, contexts) => {
7+
export const resolveOption = <T, U = ResolveContext>(predicament: ResolveOptionPredicament<T, U>, initialValue?: T): ResolveMethod<any, U> => (options, contexts) => {
88
let resolvedIndex = -1
99

1010
contexts.reduce((acc, context, index) => {

Diff for: src/utils/collection.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11

2-
export const pluck = (collection: Array<any>, key: string, callback?: (row: any) => void) => {
3-
const plucked: Array<any> = []
2+
export const pluck = <T extends Record<string, any>>(collection: T[], key: string, callback?: (row: T) => void) => {
3+
const plucked: T[] = []
44

55
for (const row of collection) {
66
if (key in row) {

Diff for: test/unit/object-merge.test.js renamed to test/unit/object-merge.test.ts

+9-7
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
import { MergeContext } from 'src/object-merge'
12
import { createProxy } from '../../src/object-merge/proxy'
23

34
describe('proxy', () => {
4-
let context
5+
let context: MergeContext<any>
6+
57
beforeEach(() => {
68
context = {
79
sources: [],
@@ -18,7 +20,7 @@ describe('proxy', () => {
1820
}
1921
}
2022

21-
const proxy = createProxy(context, target)
23+
const proxy = createProxy(context, target, {})
2224

2325
expect(proxy.str).toBe('test')
2426
expect(proxy.obj.str).toBe('test')
@@ -27,7 +29,7 @@ describe('proxy', () => {
2729
test('string (set, update, delete)', () => {
2830
const target = {}
2931

30-
const proxy = createProxy(context, target)
32+
const proxy = createProxy(context, target, {})
3133

3234
proxy.str = 'test'
3335

@@ -45,7 +47,7 @@ describe('proxy', () => {
4547
test('array (set, update, delete)', () => {
4648
const target = {}
4749

48-
const proxy = createProxy(context, target)
50+
const proxy = createProxy(context, target, {})
4951

5052
proxy.arr = [0, 1]
5153

@@ -68,7 +70,7 @@ describe('proxy', () => {
6870
test('proxy (set object)', () => {
6971
const target = {}
7072

71-
const proxy = createProxy(context, target)
73+
const proxy = createProxy(context, target, {})
7274

7375
proxy.obj = { str: 'test' }
7476

@@ -79,7 +81,7 @@ describe('proxy', () => {
7981
test('proxy (remove)', () => {
8082
const target = {}
8183

82-
const proxy = createProxy(context, target)
84+
const proxy = createProxy(context, target, {})
8385

8486
proxy.obj = { str: 'test' }
8587

@@ -93,7 +95,7 @@ describe('proxy', () => {
9395
test('proxy (remove child)', () => {
9496
const target = {}
9597

96-
const proxy = createProxy(context, target)
98+
const proxy = createProxy(context, target, {})
9799

98100
proxy.obj = { str: 'test' }
99101

0 commit comments

Comments
 (0)