kristiandupont / kanel

Generate Typescript types from Postgres
https://kristiandupont.github.io/kanel/
MIT License
887 stars 62 forks source link

Generated Database.ts is not compatible with TS 5.0 option verbatimModuleSyntax #436

Open thelinuxlich opened 1 year ago

thelinuxlich commented 1 year ago

Since TS 5.0 there is a new option called verbatimModuleSyntax which frameworks like SvelteKit set as true by default.

When this option is true, export default Database gives the following TS error:

An 'export default' must reference a value when 'verbatimModuleSyntax' is enabled, but 'Database' only refers to a type.

The solution is replacing this line:

// old
export default Database;
// new
export type { Database as default };

Workaround in .kanelrc.js

postRenderHooks: [
  (p, lines) => {
    if (p.endsWith("Database.ts")) {
        lines.pop();
        return [...lines, "export type { Database as default };"];
    }
    return lines;
  },
]
kristiandupont commented 1 year ago

Right, this is all something that I can't keep pushing much longer. I'll try to get around to looking into it soon!

seivan commented 1 year ago

There's another issue with allowImportingTsExtensions, lemme know if you want it in a separate ticket & pr. The solutions are essentially the same, with allowing (or reading tsconfig) to understand what to do.

Current hack is

      postRenderHooks: [(_path, lines) => {
        return lines.map(l => l.includes("'./") ? l.replace("\';", '.ts\';') : l)
      }],
alecmev commented 6 months ago

~import type { ... } is also preferred over import { type ... }, as it results in better elision (the import statements are completely removed, instead of being left behind as side effects).~ This is now fixed.

The above + ESM-friendly .js, this is the hook:

const verbatimModuleSyntaxHook: PostRenderHook = (_, lines) =>
  lines.map((line) => {
    let x = line;

    if (x.startsWith('import ')) {
      if (x.includes('default as') && !x.includes(', ')) {
        x = x.replace('{ default as ', '').replace('} ', '');
      }
    } else if (
      x.startsWith('export default') &&
      !x.startsWith('export default interface')
    ) {
      x = x
        .replace('export default', 'export type {')
        .replace(';', ' as default };');
    }

    if (x.includes("from './")) x = x.replace("';", ".js';");

    return x;
  });
kristiandupont commented 2 months ago

To subscribers here, the new importsExtension config field might be helpful. There is still some work to be done though.