-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
feat(typescript): Basic TypeScript support #59
Conversation
To me it looks good. Would it be hard to fully type it out? Starting with canvas props and hooks? I wonder if it would be possible at all to also incorporate threejs typings. |
Sounds good to me, I'm in the process of fixing the types in I believe |
src/canvas.tsx
Outdated
@@ -58,7 +58,7 @@ export const Canvas = React.memo( | |||
const [bind, size] = useMeasure() | |||
const [intersects, setIntersects] = useState([]) | |||
const [raycaster] = useState(() => new THREE.Raycaster()) | |||
const [mouse] = useState(() => new THREE.Vector2()) | |||
const [mouse] = useState(() => new THREE.Vector3()) |
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.
oh my, what did i do there ... good catch! 😅
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.
The promise of TypeScript is real!
Just an update, currently on vacation now, but I plan on re-visiting this afterwards! |
@setsun awesome! enjoy your time! :) |
@setsun looks really good! do you need help with something? or is this ready to go, other than the small lockfile conflicts? |
@drcmda this is mostly good to go for a good first start. I'll add some documentation on the new I'll update this tonight, and I'll let you know when it's good for review! |
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.
Just left some comments on some of the important changes. I think in a follow-up PR I would love to refine some of the foundational work here.
There are still a few type errors, but babel
will still compile the code all the same. This seems fine to me at the moment, since these are type errors that have existed in the past, and we can incrementally fix these as we go forward. Most of these are three.js
errors that I'm a little unfamiliar with.
Let me know if you have any questions! I believe after review, this should be possible to merge in.
@@ -206,6 +269,7 @@ export const Canvas = React.memo( | |||
|
|||
for (let hit of hits) { | |||
let stopped = { current: false } | |||
|
|||
fn({ |
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.
Given my current knowledge of three.js
it was hard to type the Object that is passed back in the handleIntersects
callback fn. I've left this alone for now, but would love to revisit this.
@@ -0,0 +1,100 @@ | |||
import * as THREE from 'three' |
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.
These *.d.ts
files are generated by the npm run typegen
script, and should be available for consumption by end-users. TypeScript is also pretty smart, and will generate inferred types, without any explicit types in the source code.
container.__interaction.push(instance) | ||
} | ||
|
||
instance.__handlers = handlers.reduce( |
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.
Private methods like __handlers
these are a little hard to type, since in the official three.js
types, these aren't included in the type definitions intentionally.
I think this is to discourage usage of these properties, but we could extend these types in react-three-fiber
. Still need to find out how best to do that.
im ok with all of them, could you make a last rebase/update to latest changes? then we can merge 🎉 |
@drcmda just fixed! I tried running the example from the I just ran the compiled output when Let me know if you have any issues, but looks good to me on my end 🎉 |
@setsun worked for me (examples), so i merged, thank you so much! Just the last building step crashes out (type gen)
|
@drcmda awesome! Even though the |
after this, will there be any chance to incorporate threejs types into the native element attribute types? or is this impossible to do? |
By that do you mean what @AnteGulin was suggesting here?: #11 (comment) I think it's something we can include in the |
I'm not a TS user, but i guess if i open |
Yea, you can actually specify the types of all the attributes 😁 I've started doing this, though it's only the partial subset that I'm using. I have this in a file called namespace JSX {
import { LegacyRef } from 'react'
import THREE from 'three'
import { MouseEventHandler } from 'react-three-fiber'
interface IntrinsicElements {
group: {
ref?: LegacyRef<THREE.Group>
children?: Element[] | Element
position?: THREE.Vector3
}
geometry: {
name?: string
ref?: LegacyRef<THREE.Geometry>
vertices?: THREE.Vector3[]
onUpdate?: (self: THREE.Geometry) => boolean
}
lineBasicMaterial: {
name?: string
color?: string
}
mesh: {
name?: string
ref?: LegacyRef<THREE.Mesh>
onUpdate?: (self: THREE.Mesh) => boolean
onClick?: MouseEventHandler
onHover?: MouseEventHandler
onUnhover?: MouseEventHandler
children?: Element[] | Element
geometry?: THREE.Geometry
material?: THREE.Material
scale?: THREE.Vector3
position?: THREE.Vector3
}
sphereGeometry: {
name: string
args?: [number?, number?, number?, number?, number?, number?, number?]
}
octahedronGeometry: {
name: string
}
meshBasicMaterial: {
name: string
color?: string | number
opacity?: number
transparent?: boolean
side?: THREE.Side
depthTest?: boolean
depthWrite?: boolean
args?: any
}
meshStandardMaterial: {
name: string
color?: string | number
opacity?: number
transparent?: boolean
side?: THREE.Side
depthTest?: boolean
depthWrite?: boolean
args?: any
}
meshLambertMaterial: {
name: string
color?: string | number
opacity?: number
transparent?: boolean
side?: THREE.Side
depthTest?: boolean
depthWrite?: boolean
args?: any
}
ambientLight: {
name?: string
args?: [number?, number?]
visible?: boolean
}
directionalLight: {
name?: string
args?: [string | number | undefined, number?]
position?: [number, number, number] | THREE.Vector3
visible?: boolean
}
primitive: {
object: THREE.Object3D
}
}
} A couple questions:
|
But can this be automated? B/c otherwise we have to ship a HUUUGGGEEE catalogue and maintain it, too. Not to mention that technically three-fiber isn't tied to a specific three version, it can be used with any published version. |
It might be possible to automate it, though first I think I need to find out where the information is. 😀 For example, how can I get a full list of the supported element tags? Is |
primitive can be anything, not related to three even. you could dump regular objects into the scene graph with it. that one could be impossible to type, but it's an escape hatch. |
@drcmda Which elements are supported? |
@paulmelnikow I think all elements are supported. Right @drcmda? This gets you the available tag names: import * as THREE from 'three'
type ThreeExports = typeof THREE
type Newable<T extends any[] = any[], U = any> = new (...args: T) => U
// The available tag names
type ThreeElements = {
[P in keyof ThreeExports]: ThreeExports[P] extends Newable ? P : never
}[keyof ThreeExports] As for the prop types, you might be able to use a mapped type on each class and filter out unsupported elements/props (if any) like this: type UnsupportedElements = never
// Note: All properties are assumed to be supported (but are they?)
type SupportedProps<
T extends Newable,
K extends keyof ThreeExports
> = K extends any ? keyof T : never // Note: The `extends any` part is a placeholder for `extends 'a'`
// (so we can filter by component name if necessary)
// The props of each supported component
type ThreeComponents = {
[K in keyof ThreeExports]: ThreeExports[K] extends infer T
? T extends Newable
? { [P in SupportedProps<T, K>]: T[P] }
: never
: never
} LMK how that works out |
I'm not seeing the types in the Is there a missing build step? |
Hmm, after cloning and running
|
What is |
@aleclarson it looks like the library needs to be I've only had a lil time to address the remaining type issues (which don't currently block compilation). Would welcome PRs and to collab if y'all have time on the remaining issues! |
"jsx": "react", | ||
"pretty": true, | ||
"skipLibCheck": true, | ||
"allowJs": true |
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.
Maybe enable strict?
Will result in more errors initially, but worth for the long run.
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.
export type CanvasContext = { | ||
canvas?: React.MutableRefObject<any> | ||
subscribers: Array<Function> | ||
frames: 0 |
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.
Should these two be numbers?
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.
subscribers is an array of callbacks. frames is an int.
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.
Yeah, I meant to comment on the line below, as the two 0s will be Numeric Literal Types and thus only allow actual 0 as value.
What
Adds TypeScript support to react-three-fiber by adding a
.tsconfig.json
, and changing the file extensions to.ts
/.tsx
. This gives us some decent inferred type-checking out of the box withtsc
.Also add a new npm script called
typecheck
, which callstsc --noEmit --jsx react src/*
, to perform static type-checking on the fly, which may be useful if something like CircleCI is setup for continuous integration.This is also potentially useful because Babel will compile the files, regardless of if it passes TypeScript type checks or not. 🤷♂️
Example output for
yarn run typecheck
is as follows:@drcmda would love to get your thoughts on the approach, and if you have some ideas on a public
types/
interface you would want end-users to use.To-do
types/
folder, providing public types forreact-three-fiber
to be used by end-users.