Skip to content

[p5.js 2.0 Bug Report]: Typescript declarations missing overloads/optional parameters #7862

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

Open
1 of 17 tasks
SoundOfScooting opened this issue Jun 1, 2025 · 9 comments
Open
1 of 17 tasks

Comments

@SoundOfScooting
Copy link

SoundOfScooting commented Jun 1, 2025

Most appropriate sub-area of p5.js?

  • Accessibility
  • Color
  • Core/Environment/Rendering
  • Data
  • DOM
  • Events
  • Image
  • IO
  • Math
  • Typography
  • Utilities
  • WebGL
  • Build process
  • Unit testing
  • Internationalization
  • Friendly errors
  • Other (specify if possible)

p5.js version

v2.0.3

Web browser and version

No response

Operating system

No response

Steps to reproduce this

There are many missing overloads in the generated TypeScript definitions, most of which are functions with runtime optional parameters that are not declared as optional.
Usage of these missing overloads is an error when using "strict": true in tsconfig.json.

Some examples in p5.d.ts (not an exhaustive list):

// alpha should be optional
color(v1: number, v2: number, v3: number, alpha: number): p5.Color;
background(colorstring: string, a: number): void;
background(gray: number, a: number): void;
background(v1: number, v2: number, v3: number, a: number): void;
background(image: p5.Image, a: number): void;
clear(r: number, g: number, b: number, a: number): void;
/* correct */ fill(v1: number, v2: number, v3: number, alpha?: number): void;
fill(gray: number, alpha: number): void;
stroke(v1: number, v2: number, v3: number, alpha: number): void;
stroke(gray: number, alpha: number): void;

// options should be optional
beginClip(options: object): void;
clip(callback: Function, options: object): void;

// n should be optional
redraw(n: number): void;

// both params should be optional
erase(strengthFill: number, strengthStroke: number): void;

// these empty overloads are missing
print(): void;
fullscreen(): boolean;

// these fields are missing
width: number;
height: number;

// etc

Tested using p5 instance mode.

To actually use the generated types I had to change this part of p5/package.json.

".": "./dist/app.js",
// ->
".": {
  "types": "./types/p5.d.ts",
  "default": "./dist/app.js"
},

I'm compiling to an HTML file that can be opened offline with file://, but because of CORS the HTML file cannot use JS modules and I must disable the friendly error system.
To do this I've used Parcel to bundle the files with settings "outputFormat": "global", "scopeHoist": false, but it requires me to comment out a block if (typeof P5_DEV_BUILD !== 'undefined') { inside lib/p5.js (p5.min.js works fine).

This is my current working setup (suggestions welcome):

import type * as p5 from "p5";

// for some reason p5.default has different constructor signature than p5.p5
const P5 = (globalThis.p5 as any as typeof p5.default);

// this declaration is missing
(P5 as any).disableFriendlyErrors = true;

new P5(p5 => { /* ... */ });
Copy link

welcome bot commented Jun 1, 2025

Welcome! 👋 Thanks for opening your first issue here! And to ensure the community is able to respond to your issue, please make sure to fill out the inputs in the issue forms. Thank you!

@davepagurek
Copy link
Contributor

Types are automatically generated from the inline documentation in the codebase, so these overloads or missing optionals will need to be corrected there (this means the documented function signatures are also slightly incorrect.) If anyone is interested in going through the list here (thanks for compiling it!) that would be appreciated!

@SoundOfScooting
Copy link
Author

I don't mind giving it a try. I'll also look for more discrepancies as the above list is not complete.

@perminder-17
Copy link
Collaborator

Thanks @SoundOfScooting , I have assign you this one. Thanks for the help :)

@SoundOfScooting
Copy link
Author

SoundOfScooting commented Jun 2, 2025

I'm starting work on this and notice some other issues.

As mentioned in the issue, TypeScript errors at import ... from 'p5' because exports in package.json doesn't specify the path to the type files. This issue also occurs inside the generated declarations themselves (for example, p5 constants don't appear to resolve).
I plan to include the following fix in my PR:
(The other files in this list don't have corresponding declaration files to point to, so I'm not sure what to do about them.)

-    ".": "./dist/app.js",
+    ".": {
+       "types": "./types/p5.d.ts",
+       "default": "./dist/app.js"
+    },
-    "./core": "./dist/core/main.js",
+    "./core": {
+      "types": "./types/core/main.d.ts",
+      "default": "./dist/core/main.js"
+    },

vscode(ium) also reports these syntax errors which can be made into other issues if necessary.

  • math.js:37:14: A rest parameter must be last in a parameter list.
    src: * @param {...Number} x Zero or more numbers, representing each component of the vector.
  • structure.d.ts:181:12: '(' expected.
    src: function p5: typeof p5
  • p5.Element.d.ts
    Functions and parameters named class are marked as syntax errors (methods named class are fine).
  • 2d_primitives.d.ts & 3d_primitives.d.ts
    export default function(...) in JS generates the declaration export default function 2/3d_primitives(...), which is marked a syntax error.
  • this.ingredients.shapes[f] !== [include] always returns true #6660 (which has had multiple PRs attempted and none merged)

@SoundOfScooting
Copy link
Author

SoundOfScooting commented Jun 2, 2025

Oh, it appears that I was mistaken that one of the fill overloads was correct.

I've looked into it more thoroughly. The documentation comments correctly mark parameters as optional with [], and types/color/setting.d.ts has optional parameters, but types/p5.d.ts and types/global.d.ts do not, so the issue appears to be with those portions of the generator scripts.

@davepagurek
Copy link
Contributor

davepagurek commented Jun 2, 2025

Thanks for narrowing it down @SoundOfScooting! Are you interested in trying to fix the optional handling in that file too? It looks like it is currently trying to be handled here (possibly the broken cases are going through a different code path?):

optional: param.type?.type === 'OptionalType'

For reference, for the documentation on the website and for FES, it happens here:

p5.js/utils/convert.mjs

Lines 64 to 65 in 2606c21

if (node.type === 'OptionalType') {
return { optional: 1, ...typeObject(node.expression) };

@davepagurek
Copy link
Contributor

#6660 (which has had multiple PRs attempted and none merged)

I think none of them ended up merged because someone was working on it and we didn't want people to jump the queue, but then they later closed their PR without making revisions. So I think that one is open again to be worked on, I've marked it as Help Wanted and Good First Issue.

@SoundOfScooting
Copy link
Author

Okay, I've fixed the main issue of optional parameters.

Both generateFunctionDeclaration and generateMethodDeclarations call the function generateParamDeclaration, but the former is using funcDoc (from "unorganized" data) and the latter is using item (from "organized" data), which the function is not correctly written to handle.

Organized parameters have a different format than regular ones:

p5.js/utils/helper.mjs

Lines 286 to 290 in 2606c21

params: (entry.params || []).map(param => ({
name: param.name,
type: generateTypeFromTag(param),
optional: param.type?.type === 'OptionalType'
})),

generateTypeFromTag actually strips OptionalType, so the detection in generateParamDeclaration fails. A simple fix is to change the detection to param.optional || param.type?.type === 'OptionalType'.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants