microsoft / TypeScript

TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
https://www.typescriptlang.org
Apache License 2.0
101.23k stars 12.52k forks source link

[Design Policy] Consider JSDoc feature parity with Typescript #30624

Open Jamesernator opened 5 years ago

Jamesernator commented 5 years ago

Search Terms

jsdoc parity, jsdoc equivalence, jsdoc

Suggestion

The JSDoc mode of TypeScript is very useful in cases where a build step (esp for node libraries for example) isn't desired or when other constraints prevent not writing in JS. However it can be annoying when trying to implement something that can't be expressed in JSDoc mode due to requiring Typescript syntax.

As such I would like to propose that TypeScript ensures that anything that can be written inside a .ts file can be expressed (in at least some way) within a pure javascript + jsdoc file.

In order to get an idea of the current scope needed for feature parity this is a list of issues and features that break parity between the two modes (if any are missing just say and I'll add to the list):

Checklist

My suggestion meets these guidelines:

AlCalzone commented 5 years ago
* interface

I've had some luck with @typedef: https://github.com/AlCalzone/ioBroker.js-controller/blob/9fbbb890290b07af5d9dfb7ae90bf92f2d0be178/lib/tools.js#L1329

  • function overloading

:+1:

ExE-Boss commented 5 years ago

Function overloading can be done using:

/** @type {((name: string) => Buffer) & ((name: string, encoding: string) => string))} */
const readFile = (name, encoding = null) => { … }

I discovered this purely by accident.

texastoland commented 5 years ago
  • as const

30445

steinuil commented 5 years ago

.d.ts files can contain many of these declarations without breaking JS builds, since they don't have to be imported.

AlCalzone commented 5 years ago

But they don't work for the current file, only imported ones.

steinuil commented 5 years ago

But they do!

// test.d.ts
interface X { a: string }

// test.js
/** @type {X} */
const x = { a: 'one' };

You just have to include the .d.ts files in your tsconfig.json.

By the way, many of these tricks I also discovered by pure accident; it would be nice if they were properly documented. The page dedicated to this has improved a lot recently, but there's still a lot of things I had to figure out by trial-and-error.

AlCalzone commented 5 years ago

@steinuil Ok I should be more specific then. Function overloading does not work - at least the last time I checked:

// test.d.ts
declare function test(arg1: string, arg2: number, arg3: () => void): void;
declare function test(arg2: number, arg3: () => void): void;
declare function test(arg1: string, arg3: () => void): void;
declare function test(arg3: () => void): void;

// test.js
function test(arg1, arg2, arg3) {
  // ... args are `any`
}
texastoland commented 5 years ago

Also nonNull! #23405.

weswigham commented 5 years ago

@AlCalzone function overloads only affect usages of the function, not parameter types within a function - this is true in TS, too. You need to actually annotate parameter types on the implementation (compatible with the overloads) to get checking in the function body.

ExE-Boss commented 5 years ago

Also, in function overloads, it’d be great if the implicit arg types were unknown instead of any, but that depends on #27265 (and #30813).

jonnytest1 commented 5 years ago

@global doesnt seem to work image

having them in the same file yields he same result

{ the error is cannot find name 'foo' }

thw0rted commented 5 years ago

Would e.g. #28730 fall under this umbrella? I'm trying to use JSDoc to describe existing sources that define getter/setter properties with Object.defineProperties and the only way I've found to do so is with @memberof. (For an example, see my comment on that issue.)

bennypowers commented 4 years ago

I'm using this hack to get support for the @private JSDoc tag currently. Would love to see this land in TS.

const REGEXP = /@private(?<suffix>[\n\r\s\w]+)\*\/(?<whitespace>[\n\r\s]+)(?<memberName>[\w]+)\b/g;

const source = `
export class Foo {
  /** Focuses the element. */
  focus(): void;
  /**
   * @param  {string} message
   * @return {Error}
   * @private
   */
  createError(message: string): Error;
}
`

source.replace(REGEXP, (...args) => {
  const [{suffix, whitespace, memberName}] = [...args].reverse();
  return `@private${suffix}*/${whitespace}private ${memberName}`
})
trusktr commented 9 months ago

Here's an issue for declaration merging with JSDoc: