Skip to content

Commit

Permalink
refactor: Expand optimizations
Browse files Browse the repository at this point in the history
- оптимизация производительности Expand (необходимо продолжить работу)

- ⚡️ измение интерфейса типа Collection

- упрощение типа HasVat (нужно оценить насколько влияет на производительность после оптимизации Expand)

- fix AttributeType.File type

BREAKING CHANGE
  • Loading branch information
wmakeev committed Jul 27, 2021
1 parent 9b47ba7 commit a6dabd0
Show file tree
Hide file tree
Showing 13 changed files with 182 additions and 54 deletions.
7 changes: 3 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "moysklad-api-model",
"version": "0.3.9",
"version": "0.4.0",
"description": "Объектная модель API МойСклад для TypeScript проектов",
"main": "build/src/index.js",
"types": "build/src/index.d.ts",
Expand Down Expand Up @@ -31,9 +31,8 @@
"license": "MIT",
"devDependencies": {
"json": "^11.0.0",
"moysklad": "^0.9.2",
"moysklad-extension-queue": "^0.2.1",
"prettier": "^2.2.1",
"moysklad": "^0.10.0",
"prettier": "^2.3.2",
"typescript": "^4.3.5"
}
}
6 changes: 4 additions & 2 deletions src/model/Assortment.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import type { EntityByMetaType } from '.'

export type Assortment = EntityByMetaType[
export type AssortmentMetaType =
| 'product'
| 'service'
| 'bundle'
| 'consignment'
| 'variant'] & {
| 'variant'

export type Assortment = EntityByMetaType[AssortmentMetaType] & {
stock: number
reserve: number
inTransit: number
Expand Down
2 changes: 1 addition & 1 deletion src/model/Attribute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export type AttributeJsTypeMap = {
[AttributeType.String]: string
[AttributeType.Long]: number
[AttributeType.Time]: string
[AttributeType.File]: object // TODO AttributeType.File
[AttributeType.File]: string
[AttributeType.Double]: number
[AttributeType.Boolean]: boolean
[AttributeType.Text]: string
Expand Down
9 changes: 4 additions & 5 deletions src/model/Collection.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import type { CollectionRef } from './CollectionRef'
import type { EntityByMetaType, MetaType } from './MetaType'
import type { CollectionRef, EntityRef, MetaType } from '.'

export interface Collection<T extends MetaType = MetaType>
extends CollectionRef<T> {
rows: EntityByMetaType[T][]
export interface Collection<T extends EntityRef<MetaType>>
extends CollectionRef<T['meta']['type']> {
rows: T[]
}
13 changes: 13 additions & 0 deletions src/model/HasVat.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// TODO Временно упрощено до решения проблем с производительностью
/*
export type HasVat =
| {
vatEnabled: false
Expand All @@ -7,3 +9,14 @@ export type HasVat =
vatIncluded: boolean
vatSum: number
}
*/

export type HasVat = {
vatEnabled: boolean

/** Доступно только если указано `vatEnabled = true` */
vatIncluded?: boolean

/** Доступно только если указано `vatEnabled = true` */
vatSum?: number
}
2 changes: 1 addition & 1 deletion src/model/api/endpoints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ export type EndpointInterface<
? EntityType extends DomineEntityMetaType
// GET entity/{type}
? Method extends 'GET'
? EndpointInterfaceInfo<never, Collection<EntityType>, ExpandStr>
? EndpointInterfaceInfo<never, Collection<EntityByMetaType[EntityType]>, ExpandStr>

// FIXME Нужно переделать с зависимостью от Payload
// POST entity/{type}
Expand Down
1 change: 1 addition & 0 deletions src/model/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export * from './Account'
export * from './Address'
export * from './Agent'
export * from './AgentNote'
export * from './Assortment'
export * from './Attribute'
export * from './Barcode'
export * from './CashIn'
Expand Down
83 changes: 67 additions & 16 deletions src/model/utils/Expand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,53 @@ type t1 = EntityRef<'account'> extends CollectionRef<'account'> ? true : false
/**
* Разворачивает конкретное поле в типе
*/
type ExpandField<T, K extends keyof T> = {
export type ExpandedField<T, K extends string> =
T extends Array<infer U> | Collection<infer U>
? K extends keyof U
? ExpandedField<U, K>
: `[Error] ExpandedField: Неизвестое поле '${K}' внутри списка или коллекции`

: T extends CollectionRef<infer M>
? K extends keyof EntityByMetaType[M]
? Collection<ExpandField<EntityByMetaType[M], K>>
: `[Error] ExpandedField: Неизвестое поле '${K}' внутри CollectionRef<'${M}'>`

: K extends keyof T
? T[K] extends EntityRef<infer M> | undefined

? T[K] extends CollectionRef<M>
? Collection<EntityByMetaType[M]>

: T[K] extends CollectionRef<M> | undefined
? Collection<EntityByMetaType[M]> | undefined

: T[K] extends EntityRef<M>
? EntityByMetaType[M]

: T[K] extends EntityRef<M> | undefined
? EntityByMetaType[M] | undefined

: '[Error] never-eus8s'

: T[K]

: `[Error] ExpandedField: Неизвестный путь "${K}" #9al4cs`

// prettier-ignore

/**
* Разворачивает конкретное поле в типе
*/
export type ExpandField<T, K extends keyof T> = {
[P in keyof T]: K extends P
// EntityRef | CollectionRef
? T[P] extends EntityRef<infer M> | undefined
// CollectionRef
? T[P] extends CollectionRef<M>
? Collection<M>
? Collection<EntityByMetaType[M]>

: T[P] extends CollectionRef<M> | undefined
? Collection<M> | undefined
? Collection<EntityByMetaType[M]> | undefined

: T[P] extends EntityRef<M>
? EntityByMetaType[M]
Expand All @@ -44,31 +81,42 @@ type ExpandField<T, K extends keyof T> = {
*/
export type ExpandPath<T, K extends string> =
string extends K
? never
? '[Error] ExpandPath: Неизвестный путь - string'

// i.e. `attributes`
: T extends Array<infer M>
? Array<ExpandPath<M, K>>

// i.e. `positions`
: T extends Collection<infer M>
: T extends Collection<infer U>
// ? T & { rows: ExpandPath<T['rows'], K> }
? CollectionRef<M> & { rows: ExpandPath<EntityByMetaType[M], K>[] }
// ? CollectionRef<M> & { rows: ExpandPath<EntityByMetaType[M], K>[] }
// TODO Протестировано?
? {
[P in keyof T]: P extends 'rows'
? ExpandPath<U, K>[]
: T[P]
}

// 'foo.bar'
: K extends `${infer Field}.${infer Rest}`
? Field extends keyof T
? ExpandField<T, Field> &
{
[Key in Field]: ExpandPath<ExpandField<T, Field>[Field], Rest>
}
: never
// ? Field extends keyof T
// ? ExpandField<T, Field> &
// {
// [Key in Field]: ExpandPath<ExpandField<T, Field>[Field], Rest>
// }
// : never
? {
[P in keyof T]: Field extends P
? ExpandPath<ExpandedField<T, Field>, Rest>
: T[P]
}

// 'foo'
: K extends keyof T
? ExpandField<T, K>

: never
: never // `[Error] ExpandPath: Неизвестный путь - ${K}`

// prettier-ignore

Expand All @@ -81,14 +129,17 @@ export type Expand<T, U extends string | undefined> =
? T

: string extends U
? never
? '[Error] Expand: Неизвестный путь - string'

// 'foo.bar,baz'
: U extends `${infer Path},${infer Rest}`
? ExpandPath<T, Path> & Expand<T, Rest>
? Expand<ExpandPath<T, Path>, Rest>

// 'foo.bar'
: U extends string ? ExpandPath<T, U> : never
: U extends string
? ExpandPath<T, U>

: `[Error] Expand: Неизвестный путь - ${U}`

// TODO 'positions.assortment,agent.attributes.value'
// TODO 'attributes.value,agent.attributes.value'
Expand Down
2 changes: 1 addition & 1 deletion src/tools.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { EntityByMetaType, MetaType } from './model'
import type { EntityByMetaType, EntityRef, MetaType } from './model'

export function isType<T extends MetaType>(
metaType: T,
Expand Down
14 changes: 8 additions & 6 deletions test/model/CustomerOrder.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ const customerOrderFull1: CustomerOrder = {
id: '',
name: '',
type: AttributeType.File,
value: {},
value: '',
download: {
href: '',
mediaType: MediaType.ApplicationJson
Expand Down Expand Up @@ -161,25 +161,27 @@ const t10_1 = {} as CustomerOrder

t10_1.vatEnabled

// @ts-expect-error
// TODO vatEnabled: @ts-expect-error
t10_1.vatIncluded

// @ts-expect-error
// TODO vatEnabled: @ts-expect-error
t10_1.vatSum

/* TODO vatEnabled:
if (t10_1.vatEnabled === true) {
const t1: boolean = t10_1.vatIncluded
const t2: number = t10_1.vatSum
}
*/

const t10_2 = {} as Patch<'customerorder'>

// @ts-expect-error
// TODO vatEnabled: @ts-expect-error
t10_2.vatIncluded

t10_2.vatEnabled = true

// @ts-expect-error
// TODO vatEnabled: @ts-expect-error
t10_2.vatIncluded

if (t10_2.vatEnabled) {
Expand All @@ -197,7 +199,7 @@ t10_3
const t10_4: Patch<'customerorder'> = {
vatEnabled: false,
// .. нужно явно указывать vatEnabled
// @ts-expect-error
// TODO vatEnabled: @ts-expect-error
vatIncluded: true
}
t10_4
Expand Down
6 changes: 3 additions & 3 deletions test/model/api/endpoints.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const t2: 'foo' = {} as EndpointInterface<

const t4: IsExtends<
EndpointInterface<'GET', 'entity/customerorder'>['response'],
Collection<'customerorder'>
Collection<CustomerOrder>
> = true

const t5: IsExtends<
Expand All @@ -41,7 +41,7 @@ function request<
return { method, path, body, expand } as any
}

const t6: Collection<'customerorder'> = request('GET', `entity/customerorder`)
const t6: Collection<CustomerOrder> = request('GET', `entity/customerorder`)

const id = '123-456'

Expand All @@ -51,7 +51,7 @@ const t7: CustomerOrder = request('GET', `entity/customerorder/${id}`)
const t7e: EntityRef = request('GET', `entity/customerorder3/${id}`)

// @ts-expect-error
const t6e: Collection<'customerorder'> = request(
const t6e: Collection<CustomerOrder> = request(
'GET',
`entity/customerorder/123`
)
Expand Down
9 changes: 5 additions & 4 deletions test/model/expensive.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@

import type { Collection, CustomerOrder, Expand } from '../../src'

let t10_1 = {} as Expand<Collection<'customerorder'>, 'state'>
const t10_2 = {} as Expand<Collection<'customerorder'>, 'state'>
let t10_1 = {} as Expand<Collection<CustomerOrder>, 'state'>
const t10_2 = {} as Expand<Collection<CustomerOrder>, 'state'>

t10_1.rows = [...t10_1.rows, ...t10_2.rows]

Expand All @@ -33,12 +33,13 @@ function mapOrder1(row: Expand<CustomerOrder, 'state'>) {

// .. до этого map обрезал исходный тип до CustomerOrder
const t10_3 = t10_1.rows.map(row => mapOrder1(row))
t10_3
const name: string = t10_3[0].name
name

// Но такой вариант тоже не работает

// @ts-expect-error
const t10_4: Expand<CustomerOrder, 'state'>[] = t10_1.rows.map(row =>
mapOrder1(row)
)
t10_4
t10_4[0].state?.name
Loading

0 comments on commit a6dabd0

Please sign in to comment.