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

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

Open
Jamesernator opened this issue Mar 28, 2019 · 14 comments
Open

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

Jamesernator opened this issue Mar 28, 2019 · 14 comments
Labels
Meta-Issue An issue about the team, or the direction of TypeScript

Comments

@Jamesernator
Copy link

Jamesernator commented Mar 28, 2019

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):

  • [Bug?] No way to express the object type
    • Currently in JSDoc /** @type {object} */ is equivalent to /** @type {any} */, there doesn't seem to be any way to represent const x: object purely in JS + JSDoc, this seems like a bug. Fixed
  • interface
  • abstract class
  • protected/private members Fixed
  • function overloading v5.0
  • defaults for generics
  • declare syntax in it's various forms and declaration merging
    • declare global { ... }
    • declare module "moduleName"
    • declare class Foo
    • declare interface
    • declare namespace
  • namespace
  • enum
    • /** @enum */ is not quite equivalent
  • as const v4.5
  • non-null assertion expr!

Checklist

My suggestion meets these guidelines:

  • [✓] This wouldn't be a breaking change in existing TypeScript/JavaScript code
  • [✓] This wouldn't change the runtime behavior of existing JavaScript code
  • [✓] This could be implemented without emitting different JS based on the types of the expressions
  • [✓] This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, etc.)
  • [✓] This feature would agree with the rest of TypeScript's Design Goals.
@DanielRosenwasser DanielRosenwasser added Meta-Issue An issue about the team, or the direction of TypeScript Suggestion An idea for TypeScript In Discussion Not yet reached consensus labels Mar 28, 2019
@AlCalzone
Copy link
Contributor

* interface

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

  • function overloading

👍

@ExE-Boss
Copy link
Contributor

ExE-Boss commented Apr 4, 2019

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
Copy link
Contributor

  • as const

#30445

@steinuil
Copy link

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

@AlCalzone
Copy link
Contributor

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

@steinuil
Copy link

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
Copy link
Contributor

AlCalzone commented Apr 18, 2019

@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
Copy link
Contributor

Also nonNull! #23405.

@weswigham
Copy link
Member

@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
Copy link
Contributor

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).

@DanielRosenwasser DanielRosenwasser moved this from This Week to Done in Design Meeting Docket Apr 26, 2019
@jonnytest1
Copy link

jonnytest1 commented Jun 22, 2019

@global doesnt seem to work
image

having them in the same file yields he same result

{ the error is cannot find name 'foo' }

@RyanCavanaugh RyanCavanaugh removed In Discussion Not yet reached consensus Suggestion An idea for TypeScript labels Jul 16, 2019
@thw0rted
Copy link

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
Copy link

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
Copy link
Contributor

trusktr commented Feb 27, 2024

Here's an issue for declaration merging with JSDoc:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Meta-Issue An issue about the team, or the direction of TypeScript
Projects
None yet
Development

No branches or pull requests