The Law of Demeter (also known as the Principle of Least Knowledge) is a principle in software engineering that can be very tersely explained as ‘only use one dot’. That is, code that looks like this:

1

a.c



Is preferable to code that looks like this:

1

a.b.c



Let’s apply this to React:

1

2

3

4

5

6

7

function C1 ( props ) {

return < span > {props.username} </ span > ;

}



function C2 ( props ) {

return < span > {props.user.username} </ span > ;

}



C2 depends on the structure of user , which means if you ever refactor user , you also have to refactor C2 , even though C2 only really wants a username to be rendered. C2 is therefore coupled to user .

C1 , on the other hand, only depends on the username itself, which can potentially be sourced from anywhere. This doesn’t necessarily mean more or less refactoring; the amount of refactoring is probably the same if not greater, because instead of the coupling being defined within the component, it is instead defined at the call-site of the component (the parent component), which makes the call site to user . This is usually an acceptable trade-off, though, because the parent component usually knows more about the context of the value (the user ) than the child component does.

Making code less coupled (looking more like C1 instead of C2 ) is generally considered a desirable property in codebases because it increases the potential for re-use of the code and it makes it easier to refactor code as, while there may be more places to refactor, it’s very easy to refactor the uses of this particular component.

A more obscure benefit of writing your code adhering to the law of demeter shows up when you’re using TypeScript. In TypeScript, it’s very common to define components like this:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26



export interface User {

username: string;

}





import type { User } from "./types" ;



interface Props {

user: User;

}



export default function UserPanel ( { user }: Props ) {

return < span > {user.username} </ span > ;

}





import React from "react" ;

import { render } from "@testing-library/react" ;

import UserPanel from "./UserPanel" ;



it( "should display the users name" , () => {

const user = { username : "Dan" };

const { getByText } = render( < UserPanel user = {user} /> );

expect(getByText(user.username)).toBeInTheDocument();

});



This is great and compiles just fine. What happens if I add an extra property to User , though?

1

2

3

4

interface User {

username: string ;

email: string ;

}



If we try and compile this code now our compiler will fail because our user variable in UserPanel.test.tsx does not have an email attribute. So, now we have to go and modify our test to add that attribute, even though UserPanel never actually uses that value. On one hand, this type of compile safety can be useful for encapsulation, but I’ve found it to be more trouble than it is worth.

If you instead use the approach we defined earlier this problem does not exist and it makes the code simpler to boot:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21



interface Props {

username: string;

}



export default function UserPanel ( { username }: Props ) {

return < span > {username} </ span > ;

}





import React from "react" ;

import { render } from "@testing-library/react" ;

import UserPanel from "./UserPanel" ;



it( "should display the users name" , () => {

const user = { username : "Dan" };

const { getByText } = render( < UserPanel user = {user} /> );

expect(getByText(user.username)).toBeInTheDocument();

const { getByText } = render( < UserPanel username = "Dan" /> );

expect(getByText( "Dan" )).toBeInTheDocument();

});



This becomes a real issue as you start to deal with more complicated business models. Some of the models we have in our codebase at work have at least a dozen properties and while our component only uses about 4 or 5 of them it depends on all of them due to having a dependency on the type itself rather than the constituent properties!

To summarize our learnings:

The Law of Demeter is a law of programming that posits that a.b.c is less desirable than a.b and that reducing coupling is, in general, associated with higher rates of re-use of code

is less desirable than and that reducing coupling is, in general, associated with higher rates of re-use of code This applies to React - you should avoid passing complex types through props and instead try to pass only the things the component requires

Doing this will help with testability, particularly if you’re using TypeScript

Tangentially related to all of this, I find it makes more sense in the structurally typed world to define types within your application at the call site of the component that requires them rather than defining an interface in one place and trying to share it everywhere.