Skip to content

Better typescript type inference#497

Merged
ts-thomas merged 10 commits intonextapps-de:masterfrom
flycran:master
May 6, 2025
Merged

Better typescript type inference#497
ts-thomas merged 10 commits intonextapps-de:masterfrom
flycran:master

Conversation

@flycran
Copy link
Contributor

@flycran flycran commented May 4, 2025

issue

#496 #396

Why

The meaning of this draft is to provide flexsearch with more comprehensive type inference and eliminate behavior that is inconsistent with expectations when used in typescript.

该草案存在的意义是为flexsearch提供更全面的类型推断,消除在typescript中使用时和预期不符的行为。

To disambiguate, the following will use Chinese

已完成

  • 我在最大限度保留原风格的情况下格式化了整个index.d.ts文件,增加了可读性
  • Document添加泛型,支持了文档内容的代码补全和静态类型检查
const document = new Document<{
    title: string
    description: string
    tags: string[]
}>({}); // Document<{ title: string; description: string; tags: string[] }>
const doc = await document.searchAsync({
    enrich: true,
    merge: true,
});
doc[0].doc // { title: string; description: string; tags: string[] }
  • Document的查询方法(search, searchAsync, searchCache),自动推断返回类型,不再返回联合类型,这一点非常重要且很有用
const doc1 = await document.searchAsync({
    enrich: true,
}); // EnrichedDocumentSearchResults<{ title: string; description: string; tags: string[] }>
const doc2 = await document.searchAsync({
    enrich: true,
    merge: true,
}); // MergedDocumentSearchResults<{ title: string; description: string; tags: string[] }>
  • Indexsearch等方法添加同上的支持
  • 为字段提供类型推断,包括DocumentSearchOptions.field/index/pluckDocumentDescriptor.field/index/tag/store以及所有使用了FieldName的地方
const document = new Document<{
    title: string
    description: string
    tags: {
        name: string
        id: number
    }[]
}>({
    document: {
        index: ["tags"], // "description" | "title" | "tags" | "tags[]:name" | "tags[]:id"
    },
});

计划

  • Resolver添加泛型

欢迎提出在类型方面的建议

flycran added 2 commits May 5, 2025 03:00
  支持ts类型测试

- 添加types.ts
  测试ts静态类型
  - 导出了部分类型,这是为了支持类型测试
  - 为`Document`添加泛型
  - 在`Document`实例化时传入doc的类型,它将为所有返回doc的方法提供正确的类型
  - 自动推断`search`,`searchCache`,`searchAsync`的返回类型,现在他们不再返回联合类型
  - 为上述方法的`limit`参数单独使用函数重载,增加可读性

- 更新types.ts
  测试ts静态类型
@flycran flycran mentioned this pull request May 4, 2025
flycran added 4 commits May 5, 2025 10:39
  - 重构FieldName为泛型,支持自动推断字段定义

- 更新types.ts
  测试ts静态类型
  - 为Resolver添加泛型支持

- 更新types.ts
  测试ts静态类型
This reverts commit 15a9ff3.
  - 为Index的search等方法自动推断返回类型
@flycran
Copy link
Contributor Author

flycran commented May 5, 2025

  1. 我注意到Document.search可能返回Promise,这是有意的吗?什么情况下会返回Promise?
  2. Resolver.resolve何时缩小返回到DefaultSearchResults

@flycran flycran marked this pull request as ready for review May 5, 2025 04:51
@ts-thomas
Copy link
Contributor

ts-thomas commented May 5, 2025

@flycran thanks a lot, really great work 👍

  1. Document.search can return a Promise type when the document index was created with enabled Worker, e.g. by passing the option worker: true when creating the index. The same is valid also for the methods Document.add/update/remove. Also it can return a Promise when using the method .search() on a persistent index.
  2. Resolver.resolve() will always return a non-promised value (SearchResults). The type of SearchResult depends on weather it is a document index (also depends on document store was used, enrich options passed) or basic index.

@ts-thomas ts-thomas self-assigned this May 5, 2025
@flycran
Copy link
Contributor Author

flycran commented May 5, 2025

@ts-thomas search的工作是否遵循这样的模式

const documentNoWorker = new Document({});
const doc5 = documentNoWorker.search({}); // No Promise

const documentWorker = new Document({
    worker: true,
});
const doc6 = await documentWorker.search({}) // Promise

const documentWorker2 = new Document({
    worker: '...',
});
const doc7 = await documentWorker2.search({}) // Promise

const index = new Index({})
const idx = index.search({}) // No Promise

const worker =  new Worker()
const wkr = await worker.search({}) // Promise

@ts-thomas
Copy link
Contributor

ts-thomas commented May 5, 2025

@flycran Promises are right on every listed code example 👍

additionally:

const indexPersistent = new Index();
// create db instance with optional prefix
const db = new IndexedDB("my-store");
// mount and await before transfering data
await indexPersistent.mount(db);
const db1 = indexPersistent.search({}); // Promise
const indexPersistent2 = new Index({
  db: new IndexedDB("my-store")
});
const db2 = indexPersistent2.search({}); // Promise

The same for Document ...

const documentIndexPersistent = new Document({});
// create db instance with optional prefix
const db = new IndexedDB("my-store");
// mount and await before transfering data
await documentIndexPersistent.mount(db);
const db1 = documentIndexPersistent.search({}); // Promise
const documentIndexPersistent2 = new Document({
  db: new IndexedDB("my-store"),
  document: {}
});
const db2 = documentIndexPersistent2.search({}); // Promise

@flycran
Copy link
Contributor Author

flycran commented May 5, 2025

@ts-thomas 你想表达调用mount(db)search返回Promise,但是这是不可能的,typescript只能做到静态类型推断,无法捕获到动态的方法调用。我只能为options里面的db提供类型推断

@ts-thomas
Copy link
Contributor

@flycran thanks for the hint. The most simple solution is to deprecate the using of index.mount() and only allow passing by option db when creating the instance.

@ts-thomas
Copy link
Contributor

@flycran I've added missing types for language preset imports and persistent adapter imports accordingly to #495

flycran added 3 commits May 6, 2025 17:23
  - 修复`search`的返回值类型,根据worker、db推断返回类型

- 更新types.ts
  测试ts静态类型
  - 修复`search`的返回值类型,根据worker、db推断返回类型

- 更新types.ts
  测试ts静态类型
@flycran flycran marked this pull request as draft May 6, 2025 09:30
@flycran
Copy link
Contributor Author

flycran commented May 6, 2025

@ts-thomas 你可以先将mount标记为deprecated
我已经完成了search的类型,在正确的时候返回Promise
我还需要一点时间来理解Resolver是怎么工作的,我还没有完全搞懂它。

@ts-thomas ts-thomas marked this pull request as ready for review May 6, 2025 09:44
@ts-thomas ts-thomas merged commit c25b91d into nextapps-de:master May 6, 2025
3 checks passed
@flycran
Copy link
Contributor Author

flycran commented May 6, 2025

@ts-thomas 我还有一些建议,可以考虑在下一个破坏性更新中应用

  1. 判断search是不是返回Promise很麻烦且没有必要,且可能不符合直觉,你已经有了一个searchAsync,开发者可能会认为search应该返回一个非Promise,而不是在特定条件下返回Promise。一个有效的方法是在必须返回Promise的情况下对search抛出错误,并引导开发者使用searchAsync

@ts-thomas
Copy link
Contributor

ts-thomas commented May 6, 2025

@flycran really great work, thanks a lot 💪. I need to investigate some time to understand some of the more complex definitions to keep it maintainable.
Let me help you with the Resolver. I will post you later a list of all possible states, this will makes it much easier to get an overview about all return types.

Your suggestion to use searchAsync explicitely really makes sense,. This also will increase the understanding when just reading the code. This also means, all the options which resolves into a Promise return when calling search is just supported by the method searchAsync, so it probably needs to split both options.

@PabloDinella
Copy link
Contributor

Nice job @flycran, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants