DEV Community

Discussion on: TypeScript is wasting my time

Collapse
 
joelbonetr profile image
JoelBonetR 🥇 • Edited

After working with both we ended up with a middle point solution that has become our favourite, and it's using TS + JS but not in separate files, let me explain:

You can just add TS Pragma at the top of your JS files
// @ts-check

Then declare the types you want with JSDoc

Quick example:

// @ts-check
const fs = require('fs');

/**
 * encodes a file into base64
 * @param {import('fs').PathOrFileDescriptor} file 
 * @returns {string}
 */
const base64_encode = (fileSource) => {
  /** @type {Buffer} */
  var file = fs.readFileSync(fileSource);
  return Buffer.from(file).toString('base64');
}
Enter fullscreen mode Exit fullscreen mode

If something bothers you (let's add an example):

// @ts-check
const { Sequelize } = require('sequelize');

const sequelize = new Sequelize(process.env.DB_NAME, process.env.DB_USER, process.env.DB_PASSWORD, {
  host: process.env.DB_ADDR,
  dialect: process.env.DB_DIALECT,
});
Enter fullscreen mode Exit fullscreen mode

It will complain about Type 'string' is not assignable to type 'Dialect'.ts(2322) in the dialect option.

Do I really need to create a Dialect for that when a string stored in a config/env file will do the exact same job?

I mean, I'm not going to suddenly use a different dialect on the DB, it will be the same always for this project and if I need to change something its just about editing the config/env file, migrate the models, migrate the current data... it's not something you do "by mistake" or whatever, you really need to invest time on it.

Moreover I'm not working with POO which means no custom classes are (nor will be) added to the project.

Quick fix:

// @ts-check
const { Sequelize } = require('sequelize');

const sequelize = new Sequelize(process.env.DB_NAME, process.env.DB_USER, process.env.DB_PASSWORD, {
  host: process.env.DB_ADDR,
  // @ts-ignore
  dialect: process.env.DB_DIALECT,
});
Enter fullscreen mode Exit fullscreen mode

This way (using TS pragma + JSDoc) you will

  • Get your project well documented.
  • Get type checking where and when it's really meaningful and helpful.
  • Works in dev time, handled by VSCode out of the box without the need of adding TS as dependency in your project or configuring anything.
  • No time wasted compiling (transpiling) TS to JS.
  • Faster dev times.
  • No excuses for anyone not documenting the code with fallacies like "my code is good enough to be understood by anyone so it's auto-documented" or BS like that anymore. 😆
  • Get type inference for your variables and functions either be in the same file or imported/required from another.
  • Be happier (opinionated sentence).

It's a win-win, the best of both worlds and (to me) the way to go..

We already tried it in a big project that is in production since 5 to 6 months ago (at the time of writing that).

We had 2 webapps, one with JS another one using TS and this third one using the approach described in this comment.

Now, no one in the team wants TS anymore, that was unexpected at the beginning but we're getting faster development times, the code is much more understandable by anyone new in the project, no flaws due to types, makes PR review easier and so on.

We're thinking to migrate the TS one to this approach first while adding this approach in the JS one anytime we need to edit a file, find a bug, add a feature and so on.

Thoughts on that? Have you ever tried this approach?

Collapse
 
gmartigny profile image
Guillaume Martigny

I love JSDoc and use it everywhere I can. In a personal project I use JSDoc to output types for users to consume. This is a good tradeoff for me, because I don't have to bother with TS, but my users can have their types if they need to.

I'll try your method, but I'm worry I won't like putting @ts-ignore everywhere.

Collapse
 
joelbonetr profile image
JoelBonetR 🥇

You just need to discern wherher is something verbose/unnecessary/absurd or something useful that must be provided 😂