Yesterday I had a mental meltdown with my React project. I might have mentioned that I was reading a book on working with React and a C# back-end API, and that this book was written from the perspective of using TypeScript rather than plain ol’ Javascript. TypeScript is a “superset” of Javascript, meaning it adds stuff on top of JS. In this case, it makes JS “type safe” by requiring a variable to have a specific type. Normally JS is pretty free-wheeling with it’s variables which is both a blessing and a curse because:
//Setting x equal to number 0
var x = 0;
//And then setting it to a string representation of 0
x = "0";
Both are technically legal since in this case x is not enforcing a specific data type. In the initial setting of x, we can use x in math-related hijinks, but if we tried to do math after re-assigning the value to a string, we’re going to get yelled at by the parser.
With TypeScript, variables are assigned a type, and that type is enforced:
//This is OK
let x: number = 0;
//This is not OK because we have already cast x as type number
x = "0";
I started my programming career with Visual Basic, but it wasn’t long before I detoured into ASP, which is a web scripting language that uses a subset of Visual Basic. I don’t remember if ASP actually supported data typing, but I know for a fact that it wasn’t required if it did, because miscasting value assignments was the bane of my existence. I think because I use C# on a daily basis that type safety has become muscle memory, which is why I was so hung up on TypeScript for this React project.
What does this matter? Well, in some ways it does, and some ways it doesn’t. Consider this:
//File mycomponent.tsx
export interface User {
name: string
;
address: string;
city: string;
state: string;
postal5: number;
}
export const MyComponent = ({name}:User) =>{
return(<div>Hello {name}</div>
}
//Elsewhere in the app...
import { MyComponent } from './mycomponent';
function App(){
return(
<MyComponent name="Kelly"></MyComponent>
)
)
We’ve got an interface, which is a contract that assures the object User object is going to have several properties, one of which is name of type string. Our test component accepts an instance of the User interface as an argument, but since we’re only interested in the name property within the component, we are “destructing” the argument by specifying which property or properties we want from the overall User argument we are passed. Inside the component we refer to the name property directly by enclosing it in {}.
When we render the component elsewhere in the app, we can assign a value on the component element using “name” as a property of the element. The component definition knows to expect User, so all properties of User are available as properties of the MyComponet element. Since the definition of name in the User interface is typed as a string, we have to pass a string and not a number…and not a function.
This is what killed me: getting functions passed around. In Javascript, a function is portable, meaning we can treat functions as objects, allowing us to do things like assign a function to a variable in what’s called a “named function”:
var myFunc = function(arg1, arg2) { return SOMETHING; }
console.log(myFunc(1, "Apple"));
Ideally myFunc will be defined somewhere central that other code can reach it so that we can use this function wherever we need to. And because we’ve “named” it, we don’t have to re-write the function over and over. We just call myFunc(arg1, arg2) and accept whatever is returned to us.
React respects the portability of functions, but what really stymied me was when I had to pass a function in a type safe environment. Technically, TypeScript has the concept of an “any” type, which is basically an “I dunno” value for a variable that allows the assignment of whatever content you want. The problem is that this completely negates any benefit of using TypeScript, since “any” is indicating that we don’t care about the type safety of this variable. This did not set well with me, so I spent most of the day trying to find ways of passing functions from a parent to a child component, which is necessary when a child component needs to communicate with a parent.
There are tons of examples out there for plain ol’ Javascript React, but very few for TypeScript react. I believe that TypeScript React is relatively new compare to original JS React, which means that the critical mass of examples and questions are framed using Javascript. Of the few TypeScript examples I found, the explanation was just off-center enough from my own issues that they didn’t really help me much at all.
At the end of the day, I had to have a Real Talk with myself: what benefit was I really getting from TypeScript? It may be The Future, but that future isn’t here yet; in fact, the present is owned by the past, the original reliance on plain ol’ Javascript which works, works well, and is field-tested up the wazoo. If it’s good enough for legions of users, it should be good enough for me. I still get access to the latest React v16+ features like useEffect and useState, but because JavaScript isn’t type safe, I don’t have to try and create a square peg to fit into an enforced round hole. Some might suggest that going from “enforced safety” to “anything goes” is inherently a bad idea and under most circumstances that would be true, but since React with Javascript seems to be the most widely used version of React right now, I’m going to save myself the headache of beating my head against the wall of TypeScript simply because it happened to be what I was reading about at the time, or because it fits more in line with the variable requirements I’m used to working with.