Skip to content

Commit

Permalink
fix: enable strict mode for TS types (#1466)
Browse files Browse the repository at this point in the history
## Please verify the following:

- [x] `yarn build-and-test:local` passes
- [x] I have added tests for any new features, if relevant
- [x] `README.md` (or relevant documentation) has been updated with your
changes

## Describe your PR

This PR enables strict mode for the `reactotron-core-client` codebase to
fix issues documented here:

#1430
  • Loading branch information
crutchcorn authored Oct 29, 2024
1 parent 4ed6195 commit fd8cf47
Show file tree
Hide file tree
Showing 11 changed files with 46 additions and 41 deletions.
2 changes: 1 addition & 1 deletion lib/reactotron-core-client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
"rollup-plugin-resolve": "0.0.1-predev.1",
"ts-jest": "^29.1.1",
"tslib": "^2.6.2",
"typescript": "^4.9.5",
"typescript": "^5.1.3",
"ws": "^8.14.2"
},
"eslintConfig": {
Expand Down
10 changes: 5 additions & 5 deletions lib/reactotron-core-client/src/client-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,24 @@ type BrowserWebSocket = WebSocket
/**
* Configuration options for the Reactotron Client.
*/
export interface ClientOptions<Client> extends LifeCycleMethods {
export interface ClientOptions<Client> extends Omit<LifeCycleMethods, "onCommand"> {
/**
* A function which returns a websocket.
*
* This is over-engineered because we need the ability to create different
* types of websockets for React Native, React, and NodeJS. :|
*/
createSocket?: ((path: string) => BrowserWebSocket) | ((path: string) => NodeWebSocket)
createSocket?: ((path: string) => BrowserWebSocket) | ((path: string) => NodeWebSocket) | null

/**
* The hostname or ip address of the server. Default: localhost.
*/
host?: string
host?: string | null

/**
* The port to connect to the server on. Default: 9090.
*/
port?: number
port?: number | null

/**
* The name of this client. Usually the app name.
Expand Down Expand Up @@ -55,7 +55,7 @@ export interface ClientOptions<Client> extends LifeCycleMethods {
/**
* Fires when the server sends a command.
*/
onCommand?: (command: any) => void
onCommand?: ((command: any) => void) | null

/**
* Fires when we connect to the server.
Expand Down
2 changes: 1 addition & 1 deletion lib/reactotron-core-client/src/plugins/benchmark.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const benchmark = () => (reactotron: ReactotronCore) => {
const { startTimer } = reactotron

const benchmark = (title: string) => {
const steps = []
const steps = [] as Array<{title: string, time: number, delta: number}>
const elapsed = startTimer()
const step = (stepTitle: string) => {
const previousTime = steps.length === 0 ? 0 : (steps[steps.length - 1] as any).time
Expand Down
43 changes: 23 additions & 20 deletions lib/reactotron-core-client/src/reactotron-core-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ export interface ReactotronCore {
important?: boolean
) => void
display: (config: DisplayConfig) => void
onCustomCommand: <Args extends CustomCommandArg[] = CustomCommand["args"]>(
onCustomCommand: <Args extends CustomCommandArg[] = Exclude<CustomCommand["args"], undefined>>(
config: CustomCommand<Args>
) => () => void | ((config: string, optHandler?: () => void) => () => void)
/**
Expand Down Expand Up @@ -161,9 +161,11 @@ function emptyPromise() {
return Promise.resolve("")
}

export class ReactotronImpl implements ReactotronCore {
export class ReactotronImpl
implements Omit<ReactotronCore, "options" | "plugins" | "configure" | "connect" | "use">
{
// the configuration options
options: ClientOptions<ReactotronCore>
options!: ClientOptions<ReactotronCore>

/**
* Are we connected to a server?
Expand All @@ -173,7 +175,7 @@ export class ReactotronImpl implements ReactotronCore {
/**
* The socket we're using.
*/
socket: WebSocket = null
socket: WebSocket = null as never

/**
* Available plugins.
Expand Down Expand Up @@ -221,7 +223,7 @@ export class ReactotronImpl implements ReactotronCore {
// options get merged & validated before getting set
const newOptions = Object.assign(
{
createSocket: null,
createSocket: null as never,
host: "localhost",
port: 9090,
name: "reactotron-core-client",
Expand All @@ -240,10 +242,11 @@ export class ReactotronImpl implements ReactotronCore {

// if we have plugins, let's add them here
if (Array.isArray(this.options.plugins)) {
this.options.plugins.forEach((p) => this.use(p))
this.options.plugins.forEach((p) => this.use(p as never))
}

return this as this & InferFeaturesFromPlugins<this, ClientOptions<this>["plugins"]>
return this as this &
InferFeaturesFromPlugins<this, Exclude<ClientOptions<this>["plugins"], undefined>>
}

close() {
Expand All @@ -270,7 +273,7 @@ export class ReactotronImpl implements ReactotronCore {

// establish a connection to the server
const protocol = secure ? "wss" : "ws"
const socket = createSocket(`${protocol}://${host}:${port}`)
const socket = createSocket!(`${protocol}://${host}:${port}`)

// fires when we talk to the server
const onOpen = () => {
Expand All @@ -282,7 +285,7 @@ export class ReactotronImpl implements ReactotronCore {

const getClientIdPromise = getClientId || emptyPromise

getClientIdPromise(name).then((clientId) => {
getClientIdPromise(name!).then((clientId) => {
this.isReady = true
// introduce ourselves
this.send("client.intro", {
Expand Down Expand Up @@ -352,7 +355,7 @@ export class ReactotronImpl implements ReactotronCore {
}

// this is ws style from require('ws') on node js
if ("on" in socket && socket.on) {
if ("on" in socket && socket.on!) {
const nodeWebSocket = socket as WebSocket
nodeWebSocket.on("open", onOpen)
nodeWebSocket.on("close", onClose)
Expand Down Expand Up @@ -461,7 +464,7 @@ export class ReactotronImpl implements ReactotronCore {
// here's how we're going to inject these in
const inject = (key: string) => {
// grab the function
const featureFunction = plugin.features[key]
const featureFunction = plugin.features![key]

// only functions may pass
if (typeof featureFunction !== "function") {
Expand Down Expand Up @@ -494,20 +497,20 @@ export class ReactotronImpl implements ReactotronCore {
onCustomCommand(config: CustomCommand | string, optHandler?: () => void): () => void {
let command: string
let handler: () => void
let title: string
let description: string
let args: CustomCommandArg[]
let title!: string
let description!: string
let args!: CustomCommandArg[]

if (typeof config === "string") {
command = config
handler = optHandler
handler = optHandler!
} else {
command = config.command
handler = config.handler

title = config.title
description = config.description
args = config.args
title = config.title!
description = config.description!
args = config.args!
}

// Validations
Expand Down Expand Up @@ -535,7 +538,7 @@ export class ReactotronImpl implements ReactotronCore {
}

if (args) {
const argNames = []
const argNames = [] as string[]

args.forEach((arg) => {
if (!arg.name) {
Expand Down Expand Up @@ -592,5 +595,5 @@ export function createClient<Client extends ReactotronCore = ReactotronCore>(
options?: ClientOptions<Client>
) {
const client = new ReactotronImpl()
return client.configure(options as unknown) as unknown as Client
return client.configure(options as never) as unknown as Client
}
8 changes: 4 additions & 4 deletions lib/reactotron-core-client/src/serialize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@ function getFunctionName(fn: any): string {
*
* @param {any} source - The victim.
*/
function serialize(source, proxyHack = false) {
const stack = []
const keys = []
function serialize(source: any, proxyHack = false) {
const stack = [] as any[]
const keys = [] as string[]

/**
* Replace this object node with something potentially custom.
Expand All @@ -60,7 +60,7 @@ function serialize(source, proxyHack = false) {
* @param {*} value - The value to replace.
*/
function serializer(replacer) {
return function (this: any, key, value) {
return function (this: any, key: string, value: any) {
// slam dunks
if (value === true) return true

Expand Down
9 changes: 5 additions & 4 deletions lib/reactotron-core-client/src/validate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ const isCreateSocketValid = (
createSocket: unknown
): createSocket is ClientOptions<ReactotronCore>["createSocket"] =>
typeof createSocket !== "undefined" && createSocket !== null
const isHostValid = (host: string): boolean => typeof host === "string" && host && host !== ""
const isHostValid = (host: string): boolean =>
(typeof host === "string" && host && host !== "") as boolean
const isPortValid = (port: number): boolean =>
typeof port === "number" && port >= 1 && port <= 65535
const onCommandValid = (fn: (cmd: string) => any) => typeof fn === "function"
Expand All @@ -21,15 +22,15 @@ const validate = (options: ClientOptions<ReactotronCore>) => {
throw new Error("invalid createSocket function")
}

if (!isHostValid(host)) {
if (!isHostValid(host!)) {
throw new Error("invalid host")
}

if (!isPortValid(port)) {
if (!isPortValid(port!)) {
throw new Error("invalid port")
}

if (!onCommandValid(onCommand)) {
if (!onCommandValid(onCommand!)) {
throw new Error("invalid onCommand handler")
}
}
Expand Down
2 changes: 1 addition & 1 deletion lib/reactotron-core-client/test/configure.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { createClient } from "../src/reactotron-core-client"
import WebSocket from "ws"
import { WebSocket } from "ws"

const createSocket = (path) => new WebSocket(path)

Expand Down
4 changes: 2 additions & 2 deletions lib/reactotron-core-client/test/plugin-clear.test.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { createClient, corePlugins } from "../src/reactotron-core-client"
import plugin from "../src/plugins/clear"
import WebSocket from "ws"
import { WebSocket } from "ws"

const createSocket = (path) => new WebSocket(path)

test("clears", () => {
const client: any = createClient({ createSocket })
const results = []
const results = [] as Array<{ type: string; payload: any }>
client.send = (type, payload) => results.push({ type, payload })
client.use(plugin())
expect(client.plugins.length).toBe(corePlugins.length + 1)
Expand Down
4 changes: 2 additions & 2 deletions lib/reactotron-core-client/test/plugin-logger.test.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { createClient, corePlugins } from "../src/reactotron-core-client"
import plugin from "../src/plugins/logger"
import WebSocket from "ws"
import { WebSocket } from "ws"

const createSocket = (path) => new WebSocket(path)

test("the 4 functions send the right data", () => {
const client: any = createClient({ createSocket })
const results = []
const results = [] as Array<{ type: string; payload: any }>
client.send = (type, payload) => {
results.push({ type, payload })
}
Expand Down
1 change: 1 addition & 0 deletions lib/reactotron-core-client/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"allowJs": false,
"declaration": true,
"rootDir": ".",
"strict": true,
"declarationDir": "dist/types",
"emitDeclarationOnly": true,
"emitDecoratorMetadata": true,
Expand Down
2 changes: 1 addition & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -24568,7 +24568,7 @@ __metadata:
rollup-plugin-resolve: "npm:0.0.1-predev.1"
ts-jest: "npm:^29.1.1"
tslib: "npm:^2.6.2"
typescript: "npm:^4.9.5"
typescript: "npm:^5.1.3"
ws: "npm:^8.14.2"
languageName: unknown
linkType: soft
Expand Down

0 comments on commit fd8cf47

Please sign in to comment.