Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for imported types #3

Closed
matt-pawley opened this issue May 6, 2021 · 5 comments
Closed

Support for imported types #3

matt-pawley opened this issue May 6, 2021 · 5 comments

Comments

@matt-pawley
Copy link

Hi, we are consider using typeconv on our project. Although we heavily use imported types which don't seem to be working:

A minimal reproducible example:

// a.ts

export type Foo = number;
// b.ts

import { Foo } from './a';

export type Bar = {
  foo: Foo;
};

Then running npx typeconv -f ts -t st -o out 'b.ts' produces:

Reference to missing type: Foo, ignoring

Is there anything I'm doing wrong ? Or is this something thats not currently supported?

Thanks in advance.

@grantila
Copy link
Owner

grantila commented May 8, 2021

This has been in my mind for quite some time, I haven't decided on whether to spin up the TypeScript language server, or just manually hard-code support for e.g. imports. I guess the latter is a good first step though.

I'll have a look at this.

@grantila grantila transferred this issue from grantila/typeconv May 8, 2021
@pdfowler
Copy link

pdfowler commented Oct 25, 2021

Just did my first test of the functionality (via typeconv) and ran into this (or closely related problem) pretty quickly. Within our domain model, we have several generic models with differentiated sub-models. Without imported types, there is a lot of information lost in the output types.

source types

// types/model.ts
export interface IBaseDocument {
  uuid: UUID;
  createdAt: Timestamp;
  updatedAt: Timestamp;
}
// things/model.ts
export interface IThing extends IBaseDocument {
  ... general thing fields
}
// specificThings/model.ts
export interface ISpecificThing extends IThing {
  ... specific thing fields
}

Output
After running yarn typeconv -f ts -t ts -o ts-schemas 'src/services/**/model.ts'

// documents/model.ts
export interface IBaseDocument {
  uuid: UUID;
  createdAt: Timestamp;
  updatedAt: Timestamp;
}
// things/model.ts
export interface IThing {
  ... general thing fields (only)
}
// specificThings/model.ts
export interface ISpecificThing {
  ... specific thing fields
}

I would expect either the extends to be preserved, eg: export interface ISpecificThing extends IThing (best), or the fields to be duplicated

Since the "extends X" is dropped and the parent's fields are not included, the output is invalid for our purposes.

Notes

  • I'm doing a ts->ts conversion (tsc emit ignores d.ts files when emitting declarations only), but the same occurs in the suretype output
  • Could ambient types within the output somehow allow for reference without path resolution/tsc?
  • Seems that leveraging tsc would be the way to go, but obviously would be a whole different beast to tame.

@lille-etimo
Copy link

If this was supported it would be very useful. Then an already existing project with types spread all over could be used.

@grantila
Copy link
Owner

So, a long time later, sorry for that; This is a pretty complicated topic. For this to work as expected, you'd need to implement typescript module resolution. People would be surprised if importing from './a' works, but not from './a.js' (pointing to a.ts because of how it's decided to work nowadays), and also resolving module a when from 'a' which sounds easy, but is extremely complicated with package imports/exports and whatnot. You can't just traverse node_modules anymore, you need module resolution logic.

Also, importing from multiple modules/files, you'd need to mimic TypeScript's type merging when a type is defined multiple times (this is technically needed for a single file too, but happens a lot less).

I sometimes wish things weren't so complicated, but they are 😄

I'm closing this for now, but I'm not against implementing support for it. For that to be sustainable/maintainable though, I think it would need to be a separate implementation (a part from the current barebone one), using the TypeScript language server, or babel, or any other existing project that can load modules and understand how to mix/merge types. I'd also prefer help on this in terms of pointers to existing such implementations (using the language server for similar purposes), etc. It's a big effort to undertake.

@septatrix
Copy link

Should the time come where you revisit this one day, I would like to also mention a scenario where I currently miss this feature. It is a bit more complex than only an imported type which is why I think that using the full-blow typescript compiler, language server or whatever provides a suitable API is probably the best and most robust choice. The use case is generation of OpenAPI schemas for Nuxt.js server routes. Our consumers of the API is mostly the JS Frontend which in the case of Nuxt.js already have properly typed return values, however, there are also some consumers outside of the Nuxt project. I assume the same would also apply to Next.js though I am currently not using that.

These server types can be obtained using the following:

export type Foobar = Awaited<ReturnType<typeof import("server/api/something/[id].get").default>>

The language server at least is properly able to resolve these types.

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

No branches or pull requests

5 participants