-
Notifications
You must be signed in to change notification settings - Fork 240
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
DRAFT: Ts migration #640
base: main
Are you sure you want to change the base?
DRAFT: Ts migration #640
Conversation
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.
Hey Taylor, this is a great first draft! I did a review pass for a bunch of updated examples in those MDX files (but not all of them yet). All of those changes look good to me structurally. The comments I left focused mostly on TypeScript best practices, but none of them are anything major and should be easy to fix. Structurally, these changes all look good! 🙌
cursor: { x: 0, y: 0 }, | ||
}; | ||
|
||
const slice = createSlice({ | ||
name: "state", | ||
initialState, | ||
reducers: { | ||
setCursor: (state, action) => { | ||
setCursor: (state, action: PayloadAction<Cursor>) => { |
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.
Where is this type PayloadAction
defined?
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.
part of the redux-toolkit
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.
We should import it at the top of the code snippet because it’s an addition to the previous step.
const others = useSelector<LiveBlocksState, LiveBlocksState["others"]>( | ||
(state) => state.liveblocks.others | ||
); |
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.
Correct! This type annotation is unfortunately still necessary with the current version of @liveblocks/redux
. The goal is to eventually not need this and instead let TypeScript be able to derive this type automatically, just like with our React and Zustand packages. But for now, this is indeed the way to type it 👍
export const { | ||
suspense: { | ||
RoomProvider, | ||
useOthers, // 👈 | ||
}, | ||
} = createRoomContext(client); | ||
} = createRoomContext< Storage, UserMeta>(client); |
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 type params need to be in a specific order. All of them are optional, but the order is always fixed. Each of these annotations are valid, but no others:
createRoomContext<Presence>(client);
createRoomContext<Presence, Storage>(client);
createRoomContext<Presence, Storage, UserMeta>(client);
createRoomContext<Presence, Storage, UserMeta, RoomEvent>(client);
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.
Exact, as we just start to introduce useOthers
, we need to simply define a new Presence
type in this code snippet and let the developer know that explain that a bit bellow.
@@ -337,7 +353,7 @@ function Index() { | |||
scientist: new LiveObject({ | |||
firstName: "Marie", | |||
lastName: "Curie", | |||
}), | |||
}) as Scientist, |
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.
Ideally we can avoid the as Scientist
cast here and the type def in L341-344 — they should not be necessary. Did you run into issues with this? If so, please lmk, because it may be indicative of another issue?
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.
Agree with @nvie, no cast should be necessary here.
return Math.floor(Math.random() * max); | ||
} | ||
|
||
function getRandomColor() { | ||
return COLORS[getRandomInt(COLORS.length)]; | ||
return COLORS[getRandomInt(COLORS.length)] as string; |
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.
Type casts (using the as
operator) are potential hiding places for bugs. I always try to avoid using as
and I don't think we should advertise their use in our examples, because they're frowned upon.
Instead, did you perhaps mean:
function getRandomColor(): string {
return COLORS[getRandomInt(COLORS.length)];
}
const [{ selectedShape }, setPresence] = useMyPresence(); | ||
const others = useOthers(); | ||
|
||
/* ... */ | ||
|
||
const onShapePointerDown = (e, shapeId) => { | ||
const onShapePointerDown = (e: any, shapeId: string) => { |
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.
Same as with as
operator, any
s disable TypeScript and as a result they create places where bugs can lurk. For that reason, the use of any
is frowned upon and we should not advertise that in our examples.
In this case — and in many other cases — you can replace this any
by an unknown
, which is safer:
const onShapePointerDown = (e: any, shapeId: string) => { | |
const onShapePointerDown = (e: unknown, shapeId: string) => { |
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.
ah i hadn't seen that, I had seen most examples with events either imply an implicity "any" or use the above
will change this throughout
const { x, y, fill } = shape; | ||
|
||
return ( | ||
<div | ||
onPointerDown={(e) => onShapePointerDown(e, id)} | ||
onPointerDown={(e:any) => onShapePointerDown(e, id)} |
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.
Ditto for this any
+ all other instances of any
in this file.
32e5668
to
f737b9d
Compare
f737b9d
to
14c0a3f
Compare
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.
Great start on a more tricky task that it seems!
I did a superficial review, I'll do another past tomorrow. There are a few things that are not necessarily obvious and conventions that we need to figure together. I'm going to help you on the small details :)
cursor: { x: 0, y: 0 }, | ||
}; | ||
|
||
const slice = createSlice({ | ||
name: "state", | ||
initialState, | ||
reducers: { | ||
setCursor: (state, action) => { | ||
setCursor: (state, action: PayloadAction<Cursor>) => { |
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.
We should import it at the top of the code snippet because it’s an addition to the previous step.
import { createClient } from "@liveblocks/client"; | ||
import { createRoomContext } from "@liveblocks/react"; | ||
import { Presence, UserMeta, Storage } from "./types"; |
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.
"./types" does not exist here and we didn't introduce Presence
, UserMeta
and Storage
yet. These should come in a future step.
|
||
const client = createClient({ | ||
publicApiKey: "{{PUBLIC_KEY}}", | ||
}); | ||
|
||
|
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.
Extra line to be removed
export const { | ||
suspense: { | ||
RoomProvider, | ||
useOthers, // 👈 | ||
}, | ||
} = createRoomContext(client); | ||
} = createRoomContext< Storage, UserMeta>(client); |
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.
Exact, as we just start to introduce useOthers
, we need to simply define a new Presence
type in this code snippet and let the developer know that explain that a bit bellow.
@@ -176,15 +184,16 @@ we call this _presence_. | |||
We can use _presence_ to hold any object that we wish to share with others. An | |||
example would be the pixel coordinates of a user’s cursor: | |||
|
|||
```js | |||
cursor: { x: 256, y: 367 } | |||
```ts |
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.
At this step, I would not use any typescript definition.
@@ -12,8 +12,15 @@ import styles from "./Avatar.module.css"; | |||
*/ | |||
|
|||
const IMAGE_SIZE = 48; | |||
//convert to typescript | |||
export interface AvatarProps { |
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 be renamed to Props
because we're in a single file component. This is a common convention.
|
||
export function Avatar({ picture, name }) { | ||
//convert component to typescript |
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.
To remove
@@ -2,6 +2,7 @@ import { AppProps } from "next/app"; | |||
import Head from "next/head"; | |||
import "../styles/globals.css"; | |||
|
|||
|
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.
Extra line
@@ -11,7 +11,7 @@ import Cursor from "../components/Cursor"; | |||
import FlyingReaction from "../components/FlyingReaction"; | |||
import ReactionSelector from "../components/ReactionSelector"; | |||
import useInterval from "../hooks/useInterval"; | |||
|
|||
//// |
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.
To remove
@@ -0,0 +1 @@ | |||
LIVEBLOCKS_PUBLIC_KEY="pk_dev_w56d3kiUtvotjLov9whFziBf" |
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.
To remove. It's probably missing from our .gitignore because keys should never be commited.
This PR is a rough draft/ first step at updating our documentation----> typescript. I will probably need to iterate on this after review since this is my first experience with TS and it touched a lot of files/ code.