Skip to content

Commit

Permalink
feat(utils): Patch
Browse files Browse the repository at this point in the history
add type utils folder
  • Loading branch information
wmakeev committed Jul 4, 2021
1 parent bd43680 commit dbf0a65
Show file tree
Hide file tree
Showing 7 changed files with 194 additions and 6 deletions.
6 changes: 4 additions & 2 deletions src/model/MetaType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type {
ContactPerson,
Counterparty,
CustomerOrder,
CustomerOrderPosition,
Demand,
Employee,
Entity,
Expand All @@ -12,6 +13,7 @@ import type {
RetailDemand,
State
} from '.'
import type { Attribute } from './Attribute'
import type { InvoiceIn } from './InvoiceIn'
import type { InvoiceOut } from './InvoiceOut'

Expand Down Expand Up @@ -110,7 +112,7 @@ export enum MetaType {
export type EntityByMetaType = {
[MetaType.Account]: Account
[MetaType.AccumulationDiscount]: Entity<MetaType.AccumulationDiscount>
[MetaType.AttributeMetadata]: Entity<MetaType.AttributeMetadata>
[MetaType.AttributeMetadata]: Attribute
[MetaType.BonusProgram]: Entity<MetaType.BonusProgram>
[MetaType.Bundle]: Entity<MetaType.Bundle>
[MetaType.BundleComponent]: Entity<MetaType.BundleComponent>
Expand All @@ -131,7 +133,7 @@ export type EntityByMetaType = {
[MetaType.CustomEntity]: Entity<MetaType.CustomEntity>
[MetaType.CustomEntityMetadata]: Entity<MetaType.CustomEntityMetadata>
[MetaType.CustomerOrder]: CustomerOrder
[MetaType.CustomerOrderPosition]: Entity<MetaType.CustomerOrderPosition>
[MetaType.CustomerOrderPosition]: CustomerOrderPosition
[MetaType.CustomTemplate]: Entity<MetaType.CustomTemplate>
[MetaType.Demand]: Demand
[MetaType.DemandPosition]: Entity<MetaType.DemandPosition>
Expand Down
5 changes: 4 additions & 1 deletion src/model/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ export * from './DocumentWithPositions'
export * from './Employee'
export * from './Entity'
export * from './EntityRef'
export * from './Expand'
export * from './Group'
export * from './HasAttributes'
export * from './HasCreated'
export * from './HasDeleted'
export * from './HasFiles'
export * from './HasProject'
export * from './HasRate'
Expand All @@ -46,5 +46,8 @@ export * from './RetailDemand'
export * from './State'
export * from './TaxSystem'

// Utility types
export * from './utils'

// Reports
export * from './reports'
4 changes: 2 additions & 2 deletions src/model/Expand.ts → src/model/utils/Expand.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { EntityRef } from './EntityRef'
import type { EntityByMetaType } from './MetaType'
import type { EntityRef } from '../EntityRef'
import type { EntityByMetaType } from '../MetaType'

type ExpandEntityRef<T, K extends keyof T> = {
[P in keyof T]: K extends P
Expand Down
37 changes: 37 additions & 0 deletions src/model/utils/Patch.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import type { WritableKeys } from '.'
import type { CollectionRef, EntityByMetaType, MetaType } from '..'
import type { Entity } from '../Entity'
import type { EntityRef } from '../EntityRef'

// prettier-ignore

export type Patch<
T extends Entity<U> | Entity<U>[],
U extends MetaType = MetaType
> =
// Patch<Entity>
T extends Entity<U>
? Partial<
{
[P in WritableKeys<T>]:
// Коллекция МойСклад (positions)
T[P] extends CollectionRef<infer M> | undefined
? (Patch<EntityByMetaType[M]> & EntityRef<M>)[] | undefined

// Массив сущностей (attributes)
: T[P] extends Array<Entity<infer M>> | undefined
? (Patch<EntityByMetaType[M]> & EntityRef<M>)[] | undefined

// Default
: T[P]
}
>

// Patch<Entity[]> ->
: T extends Array<infer M>
// -> Entity
? M extends Entity<U>
? Array<Patch<M> & EntityRef<U>>
: never

: never
35 changes: 35 additions & 0 deletions src/model/utils/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
export * from './Expand'
export * from './Patch'

// https://stackoverflow.com/questions/49579094/typescript-conditional-types-filter-out-readonly-properties-pick-only-requir

export type IfEquals<X, Y, A = X, B = never> = (<T>() => T extends X
? 1
: 2) extends <T>() => T extends Y ? 1 : 2
? A
: B

export type ReadonlyKeys<T> = {
[P in keyof T]-?: IfEquals<
{ [Q in P]: T[P] },
{ -readonly [Q in P]: T[P] },
never,
P
>
}[keyof T]

export type WritableKeys<T> = {
[P in keyof T]-?: IfEquals<
{ [Q in P]: T[P] },
{ -readonly [Q in P]: T[P] },
P
>
}[keyof T]

// https://medium.com/@KevinBGreene/typescript-modeling-required-fields-with-mapped-types-f7bf17688786
export type RequireKeys<T, K extends keyof T> = {
[X in Exclude<keyof T, K>]?: T[X]
} &
{
[P in K]-?: T[P]
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { CustomerOrder, Expand } from '../../src'
import type { CustomerOrder, Expand } from '../../../src'

// Expand EntityRef
const test1 = {} as Expand<Expand<CustomerOrder, 'agent'>, 'state'>
Expand Down
111 changes: 111 additions & 0 deletions test/model/utils/Patch.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import { Attribute, CustomerOrder, MetaType, Patch } from '../../../src'

//#region Патч объекта
const t1 = {} as Patch<CustomerOrder>

// @ts-expect-error
t1.id // should omit readonly fields

// @ts-expect-error
t1.name.toString() // should make fields optional

t1.name?.toString()

t1.positions = [
{
meta: { type: MetaType.CustomerOrderPosition, href: '' },
price: 12300,
discount: 10
}
]

t1.positions = [
// @ts-expect-error
{
// У элемента коллекции должен быть обязательно указан meta
// meta?
price: 12300,
discount: 10
}
]

t1.attributes = [
{
meta: {
type: MetaType.AttributeMetadata,
href: ''
},
value: 123
}
]

t1.attributes = [
{
meta: {
type: MetaType.AttributeMetadata,
href: ''
},
value: ''
}
]

t1.attributes = [
// @ts-expect-error
{
value: ''
}
]

t1.attributes = [
{
meta: {
type: MetaType.AttributeMetadata,
href: ''
},
// @ts-expect-error
name: '',
value: ''
}
]
//#endregion

//#region Патч коллекции
const t4: Patch<CustomerOrder[]> = [
{
meta: {
type: MetaType.CustomerOrder,
href: ''
},
name: 'foo',
attributes: [
{
meta: {
type: MetaType.AttributeMetadata,
href: ''
}
}
],
positions: [
{
meta: { type: MetaType.CustomerOrderPosition, href: '' },
price: 45,
discount: 10
}
]
}
]
//#endregion

//#region Патч вложенной коллекции МойСклад
const attribute1: Patch<Attribute> = { value: 42 }

const attribute2: Patch<Attribute[]> = [
{
meta: {
href: '',
type: MetaType.AttributeMetadata
},
value: 42
}
]
//#endregion

0 comments on commit dbf0a65

Please sign in to comment.