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
TS: Change Geometric Object property types to generics #19299
Conversation
I think that using generics would be an improvements to the type definitions, and that this is a good direction, but unfortunately I'm not able to approve this change. Doing so will require testing, preferably from someone who already has a nontrivial TypeScript project using three.js, and I don't feel that I can do that right now. A few things should be checked:
Perhaps @samuelint, @jedahan, or @fms-cat can comment? It looks like this change would also be covered by #18720, although there are other changes. |
Yes, I think this PR is a duplicate of #18720 that has several resourceful discussions. It seems @jedahan -san is so busy though...
That is a discussion I've never seen in #18720 and I think that is important. |
It is possible to provide default values for generics in more recent versions of TypeScript (microsoft/TypeScript#13487), see Generic Parameter Defaults in TypeScript. I have never seen or used that before though. Otherwise they are required. |
Yeah i think that's another question, is there some reasonable version of TS that's considered current, but not bleeding edge? |
What is the effect of assigning something to the generic, i'm not yet familiar with this syntax? But to confirm this seems like a duplicate. |
The second point seems like it's resolved with this, if it fits the TS version.
Not sure how to investigate this. The syntax seems to remain, ie there's no need to do Lint testing the examples spits out a bunch of warnings, but none seem to be related to this. Lint alone reported nothing, so i assume no warnings or errors? |
@@ -5,11 +5,14 @@ import { Skeleton } from './Skeleton'; | |||
import { Mesh } from './Mesh'; | |||
import { BufferGeometry } from '../core/BufferGeometry'; | |||
|
|||
export class SkinnedMesh extends Mesh { | |||
export class SkinnedMesh < |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it actually needed to use <> if the super class already has it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's necessary, yes, unless a parent class has overridden the generic types with discrete types. For example:
class A<T> {}
// Must parameterize T.
class B extends A<String> {};
// Parameterization not needed.
class C extends B {}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Although, maybe not with defaults? I haven't tested those before.
I've added the default generics, which seems to have made some issues go away and touched the rest of the geometric |
Also could you refer this comment to add default types for these constructors? Edit: Oh, you already were seeing the comment. Thanks |
This is an interesting topic. Since DefinitelyTyped says they are not going to support TS versions that is over 2 year old, I think we can say versions that is lower than 3.0 are out of scope. |
also mark this PR to close #19072 maybe? |
Done. |
Renamed to |
Yes, I think we are very ok to use default type parameters here. So many modules in DefinitelyTyped utilizes it, since it's a feature that provides us an ability to gain both compatibility (with JS) and extensibility at once. |
All three of the issues that @donmccurdy i think pass now, i'm not sure what else to look at, but i'd like to test it some more. I wanted to ask about the testing approach, is it possible to merge this in dev and expect issues to be reported, or would it be better to increase the confidence that the PR would break as few things as possible? I'd also like to squash this, not sure if the author should do it, or happens automatically? |
@donmccurdy looks good? |
If merged to dev i can be referenced for any issues that arise. |
@pailhead You will need to do your own squashing. |
Actually, this is no longer just for Mesh but several classes. Does this title make sense? |
52e2fd5
to
9e22a34
Compare
This change looks OK to me, but I don't really have a way to test it... I'm hoping someone using three.js in an existing TS project can test it (e.g. checkout the PR, run |
@donmccurdy Ah, I did try that, but I did it with |
Sounds good — Yeah, the actual/runtime default is a discrete type (MeshBasicMaterial), but the type definition's default is a superset of all possible values, which I think is correct. |
@donmccurdy Hmm, I changed it to |
Hmm, could this be a typescript version issue or something? I’m not getting errors on my end. |
Also feel free to test the geometry as well. It should pick up the properties between g and bufferg. |
@pailhead I'm on 3.7.5 of typescript, which in fact does look a bit out of date. What version are you testing? |
A bit newer 3.8 something but it doesn’t seem like it should be affected, it’s recent enough? Did you link properly? |
@donmccurdy I didn’t understand your comment about the mesh coming from a loader. The expectation is that even a loader should type the Mesh properly when passing the material/geometry type. Do you expect the same? Ie no syntax should be changed in a typescripted loader, but we should see the benefit? |
@elalish if you're in VSCode and hover over the @pailhead the type of material coming from the loader is not available at compile time; TypeScript doesn't know what you're going to load. For something like OBJLoader maybe you could override the loader's type definitions, knowing that MTLLoader can only create MeshPhongMaterial, but TS won't know that. |
First off, to not freak out @mrdoob this is unrelated to the change, it's just conversation, this seems like it's good to go pending tests. @donmccurdy Is the first stumbling point that this is sort of beyond interfaces, ie. if this code were in typescript, it would actually type correctly, based on whatever instance is in this |
I'm not suggesting we change any loaders. Technically you could write a loader in TS that might provide better type information to the user, but it's complicated in several ways that I'd rather not get into. |
But can you at least help me clarify this without getting too much into it :) My understanding is that since we only expose interfaces, without implementation in TS, that this default generics, or generics in general cannot reach as deep. Ie. there is no way for me to define an interface to the loader (except maybe by explicitly doing |
To have type information from a loader written in JS, you would need to update its type definitions to something like: type ObjLoaderResult = Mesh<BufferGeometry, MeshPhongMaterial>;
load(url: string, onLoad: (result: ObjLoaderResult): void, ...): void That becomes unsolvable in a method that returns Group or Scene, without decorating all sorts of new things with type information. The generic types in this PR will help users who are creating Mesh and Material instances in their own TypeScript code. It will not affect the results of methods that return Group or Scene instances, or whose return types are not known at compile time, even if those methods are written in TypeScript. |
Right, there is no way to cast it from just some arbitrary data thats loaded. Works with OBJ since it only returns one type, so the whole loader can be cast. Thanks for clarifying. |
@elalish any luck? |
@pailhead No, but I'm guessing it's because I'm using the properties in a different function than where the mesh is defined (I made it a member variable). I don't think TS is smart enough to push those types across a boundary like that. That is part of why this change seems pretty narrow to me. To really get materials to be more easily usable, we'd need to get rid of |
Any chance you could post some code to illustrate your situation? @mrdoob I think at best this solves the issue people have posted about, at worst it won’t do anything. Any chance it could be merged? |
I agree, it looks okay to merge this. |
Looks like it. Though Does this PR cover all the geometry/material objects in the core? |
If you can change the core declaration files without breaking the one in the examples file I'm okay with that.
I would say yes. |
Thanks! |
ohhhh it got merged, thanks! |
This seems to resolve the issue, and when using the same syntax, you can get the expected type.
With this,
myMesh.material
will be of typeMeshBasicMaterial
.How to format this,
and should there be an alias given to(no, because some classes use different signatures egFoo | Bar
orFoo | Foo[]
?InstancedMesh
)Fixes #19072.