Add TypeScript To An Existing React Project
Learn how to add TypeScript to your existing React project in a few simple steps.
In TypeScript, it's common to feel frustration that you can't use dot notation to access type properties.
ts
typePerson = {name : string;age : number;};typeCannot access 'Person.name' because 'Person' is a type, but not a namespace. Did you mean to retrieve the type of the property 'name' in 'Person' with 'Person["name"]'?2713Cannot access 'Person.name' because 'Person' is a type, but not a namespace. Did you mean to retrieve the type of the property 'name' in 'Person' with 'Person["name"]'?Name =Person .name ;
But there are several good reasons the TypeScript team hasn't implemented it.
ts
typePerson = {name : string;age : number;};typeName =Person ["name"];typeAllValues =Person ["name" | "age"];
You're used to two different syntaxes in JavaScript for accessing property values:
ts
constperson = {name : "Ada",age : 42,};// Dotsconstname =person .name ;// Square bracketsconstage =person ["age"];
So why does TypeScript only allow the second syntax?
ts
typePerson = {name : string;age : number;};typeCannot access 'Person.name' because 'Person' is a type, but not a namespace. Did you mean to retrieve the type of the property 'name' in 'Person' with 'Person["name"]'?2713Cannot access 'Person.name' because 'Person' is a type, but not a namespace. Did you mean to retrieve the type of the property 'name' in 'Person' with 'Person["name"]'?PersonName =Person .name ;typePersonAge =Person ["age"];
The error discovered above is usefully phrased.
'Person' is a type, but not a namespace.
TypeScript namespaces are a way of grouping together types and values into a single spot.
And unlike types, they allow you to use the dot notation OR square bracket notation to access their members.
ts
namespaceMyMath {export constPI = 3.14;export typeVector = {x : number;y : number;};}constpi =MyMath ["PI"];typeVector =MyMath .Vector ;
Namespaces are, in general, out of favor. They were brought in as a potential solution to 'modules' in JavaScript before ES Modules came along - so they're a legacy feature.
Namespaces also compile to runtime code. The code above will end up looking like this:
ts
var MyMath;(function (MyMath) {MyMath.PI = 3.14;})(MyMath || (MyMath = {}));const pi = MyMath["PI"];
So - namespaces are really just objects, and objects can be accessed with dot notation or square bracket notation.
All this to say - we now understand the error we were getting before. But why is it happening in the first place?
Let's take another look at our property access syntax:
ts
typePerson = {name : string;age : number;};typeName =Person ["name"];
It's important to remember that this wasn't always available in TypeScript.
Specifically, it's called Indexed Access Types, and it landed in TypeScript 2.1 in 2016.
When the TypeScript team ships a new feature, they tend towards minimum syntactical impact. In other words - the fewest possible syntaxes for doing the same thing.
So, when they added the ability to access properties on types, they only chose one syntax - square bracket notation.
Square bracket notation is far more flexible than dot notation. For example, it lets you accept unions:
ts
typePerson = {name : string;age : number;};typeValues =Person ["name" | "age"];
Or even another type - perhaps extracted from the target itself. A popular pattern is to pass keyof
to an indexed access type:
ts
// Simple Object values!typeValues2 =Person [keyofPerson ];
A version of this with dot notation would be hard to imagine:
ts
type Person = {name: string;age: number;};// Bleughtype Values = Person.(keyof Person);
So - the TypeScript team chose the most flexible syntax and left it at that.
The TypeScript team is very careful about adding new syntax to the language, and they're unlikely to add new syntax for a feature that's already possible.
Remco Haszing on Twitter also pointed out that bringing in this syntax would conflict with the namespace syntax:
TypeScript lets you declare an interface with the same name as a namespace - meaning the access notation acts as a differentiator between the type and the namespace.
ts
namespaceMyMath {export typePI = 3.14;}interfaceMyMath {PI : number;}// Resolves to the typetypePi =MyMath ["PI"];// Resolves to the namespacetypePi2 =MyMath .PI ;
Gross - but this is the kind of thing that the TypeScript team has to consider when adding new syntax.
So, it's highly unlikely. We'll be stuck with our square bracket notation for a while yet.
Share this article with your friends
Learn how to add TypeScript to your existing React project in a few simple steps.
Learn the essential TypeScript configuration options and create a concise tsconfig.json file for your projects with this helpful cheatsheet.
Big projects like Svelte and Drizzle are not abandoning TypeScript, despite some recent claims.
Learn different ways to pass a component as a prop in React: passing JSX, using React.ComponentType, and using React.ElementType.
Learn about TypeScript performance and how it affects code type-checking speed, autocomplete, and build times in your editor.
When typing React props in a TypeScript app, using interfaces is recommended, especially when dealing with complex intersections of props.