DeveXtreme-键入严格数据源

问题描述 投票:0回答:0

我们试图拥有一个非常严格的前端。 DeVexTreme支持数据源的通用类型,但是根本没有验证。

sissue:

在以下示例中,我通过在加载功能中获得的响应中传递了不同的通用类型。这应该丢弃类型错误,但不是,这是非常令人沮丧的,因为这不会帮助我们使前端更加严格。

const myDataSource = new DataSource<MyResponseDto, number>({ load: (options) => myFunction(options) //returns Promise<LoadResult<MyOtherResponseDto>> })

目前,为了避免此问题,我为数据源做了一个包装程序类,因此我从
load

函数中推断出类型并将其传递给数据源,此外,我也必须覆盖几种类型,因为它们始终具有

any
的类型。但是我想知道是否有一个更好且本地的解决方案,这不会让我写额外的包装器并维护它...
我们正在使用

devextreme

devextreme-angular
版本:
24.1.7
我也在DeVexpress支持中心发布了一张支持票。

电流解决方案(包装器):

datasourceFactory.ts

/** * A factory class to produce strongly typed DevExtreme data sources. */ export class DataSourceFactory<TLoadOptions extends Pick<CustomStoreOptions<any, any>, "load">> { private readonly storeOptions: TLoadOptions; constructor(storeOptions: TLoadOptions) { this.storeOptions = storeOptions; } /** * Creates an `ExtendedDataSource` by merging the given `storeOptions` and any * additional custom store options (except `load` which is enforced in the constructor). */ public createDataSource( additionalOptions?: Omit< CustomStoreOptions<ExtractItemType<TLoadOptions>, ExtractKeyType<TLoadOptions>>, "load" | "key" > & { key: keyof ExtractItemType<TLoadOptions> | Array<keyof ExtractItemType<TLoadOptions>> } ): ExtendedDataSource<ExtractItemType<TLoadOptions>, ExtractKeyType<TLoadOptions>> { const mergedOptions: CustomStoreOptions<ExtractItemType<TLoadOptions>, ExtractKeyType<TLoadOptions>> = { ...this.storeOptions, ...(additionalOptions as CustomStoreOptions), }; return new ExtendedDataSource<ExtractItemType<TLoadOptions>, ExtractKeyType<TLoadOptions>>(mergedOptions); } }

ExtendedDataSource.ts:

/** * An extension of DevExtreme's DataSource with a typed `columns()` helper. * * @internal * @deprecated do not use this method. Use `DataSourceFactory` instead. This is for internal purposes only */ export class ExtendedDataSource<TItem, TKey = number> extends DataSource< TItem, TKey > { constructor(options: CustomStoreOptions<TItem, TKey>) { super(options); } /** * Returns a proxy-based column accessor for type-safe property paths. * * generic type T is required */ public columns = <T extends TItem = never>() => { return getColumns<T>(); }; // The overrides below simply ensure TypeScript picks up TItem[] correctly. public override items(): TItem[] { return super.items(); } public override load(): DxExtendedPromise<TItem[]> { return super.load(); } public override reload(): DxExtendedPromise<TItem[]> { return super.reload(); } }
types.ts:

/** * @internal * Extracts the 'item' type from an object whose `load` method returns a `Promise<LoadResult<T>>`. */ export type ExtractItemType<T> = T extends { load: (options: any) => Promise<LoadResult<infer U>>; } ? U : unknown; /** * @internal * Extracts the 'key' type from an object whose `byKey` method accepts `key`. * Fallback to `number` if not defined. */ export type ExtractKeyType<T> = T extends { byKey?: (key: infer K, extraOptions?: any) => PromiseLike<any>; } ? K : number; /** * @internal */ export interface StringCallable { (): string; } /** * @internal */ export type PropertiesOf<T> = T extends any[] ? StringCallable : T extends object ? { [K in keyof Required<T>]-?: PropertiesOf<T[K]> } & StringCallable : StringCallable;

I为我的包装器提供了一个额外的功能,以获取所有可能的功能。
GetColumns.ts:

dataField

示例包装器的用法:
/**
 * @internal
 * @deprecated do not use this method. Use `DataSourceFactory` instead. This is for internal purposes only
 */
export function getColumns<T>(path: string = ""): PropertiesOf<T> {
  return new Proxy((() => path) as StringCallable, {
    get: (_target, prop: string) => {
      const newPath = path ? `${path}.${prop}` : prop;
      return getColumns(newPath);
    },
    apply: (_target, _thisArg, _args) => path,
  }) as PropertiesOf<T>;
}

readonly #dataSourceFactory = new DataSourceFactory({
    load: (options) => myFunction(options), //returns Promise<LoadResult<MyResponseDto>>
});
readonly dataSource = this.#dataSourceFactory.createDataSource({
    key: "id", //key can be keyof MyResponseDto or an array of those keys
    insert: (values) => myPostFunction(values), //values has the type: MyResponseDto and return value must be Promise<MyResponseDto>
    update: (key, values) =>myPutFunction(key, JSON.stringify(values))), //values has the type: MyResponseDto & key has the type: number
});
readonly columns = this.dataSource.columns<MyResponseDto>(); //if the right generic is not passed, error is thrown. The reason to pass the generic is because of the limitations in angular html template

看起来,您已经完成了围绕DeVextreme的数据源的类型限制工作的彻底工作。包装器解决方案是强制执行类型安全性的绝佳方法,但我可以理解如何保持繁琐。希望DeVextreme能够在未来版本中增强其类型检查,以避免使用这些解决方法。对于从事其他类型项目的任何人,请不要忘记查看
custom研究论文服务
它们可能是有效完成学术任务的宝贵资源!

typescript devextreme devextreme-angular
最新问题
© www.soinside.com 2019 - 2025. All rights reserved.