惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

大猫的无限游戏
大猫的无限游戏
K
Kaspersky official blog
Apple Machine Learning Research
Apple Machine Learning Research
B
Blog
aimingoo的专栏
aimingoo的专栏
M
MIT News - Artificial intelligence
小众软件
小众软件
云风的 BLOG
云风的 BLOG
腾讯CDC
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Hugging Face - Blog
Hugging Face - Blog
S
SegmentFault 最新的问题
Stack Overflow Blog
Stack Overflow Blog
量子位
S
Secure Thoughts
G
GRAHAM CLULEY
C
CXSECURITY Database RSS Feed - CXSecurity.com
人人都是产品经理
人人都是产品经理
雷峰网
雷峰网
T
Threat Research - Cisco Blogs
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Cisco Talos Blog
Cisco Talos Blog
G
Google Developers Blog
爱范儿
爱范儿
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
有赞技术团队
有赞技术团队
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Martin Fowler
Martin Fowler
The GitHub Blog
The GitHub Blog
Google DeepMind News
Google DeepMind News
C
Cisco Blogs
D
Darknet – Hacking Tools, Hacker News & Cyber Security
博客园 - 聂微东
宝玉的分享
宝玉的分享
H
Hackread – Cybersecurity News, Data Breaches, AI and More
N
Netflix TechBlog - Medium
Forbes - Security
Forbes - Security
Engineering at Meta
Engineering at Meta
S
Security Affairs
Help Net Security
Help Net Security
博客园 - 三生石上(FineUI控件)
AWS News Blog
AWS News Blog
博客园 - 叶小钗
Recent Commits to openclaw:main
Recent Commits to openclaw:main
V2EX - 技术
V2EX - 技术
Hacker News: Ask HN
Hacker News: Ask HN
Project Zero
Project Zero
H
Heimdal Security Blog
W
WeLiveSecurity
C
Check Point Blog

Dmitri Pavlutin Blog

Pure Functions in JavaScript: A Beginner's Guide Record Type in TypeScript: A Quick Intro How to Write Comments in React: The Good, the Bad and the Ugly 4 Ways to Create an Enum in JavaScript React forwardRef(): How to Pass Refs to Child Components TypeScript Function Types: A Beginner's Guide How to Use v-model to Access Input Values in Vue Mastering Vue refs: From Zero to Hero Environment Variables in JavaScript: process.env 5 Must-Know Differences Between ref() and reactive() in Vue How to Destructure Props in Vue (Composition API) Triangulation in Test-Driven Development How to Use nextTick() in Vue Programming to Interface Vs to Implementation A Smarter JavaScript Mapper: array.flatMap() Array Grouping in JavaScript: Object.groupBy() How to Access ES Module Metadata using import.meta JSON Modules in JavaScript How to Trim Strings in JavaScript TypeScript Function Overloading How to Debounce and Throttle Callbacks in Vue How to Show/Hide Elements in Vue Sparse vs Dense Arrays in JavaScript How to Fill an Array with Initial Values in JavaScript Covariance and Contravariance in TypeScript What are Higher-Order Functions in JavaScript? Index Signatures in TypeScript How to Use React useReducer() Hook unknown vs any in TypeScript A Guide to React Context and useContext() Hook How to Use Promise.any() 2 Ways to Remove a Property from an Object in JavaScript 'return await promise' vs 'return promise' in JavaScript How to Use Promise.allSettled() How to Use fetch() with JSON JavaScript Promises: then(f,f) vs then(f).catch(f) What is a Promise in JavaScript? How to Use Promise.all() A Simple Guide to Component Props in React Don't Stop Me Now: How to Use React useTransition() hook A Simple Explanation of JavaScript Variables: const, let, var ES Modules Dynamic Import How to Memoize with React.useMemo() How to Cleanup Async Effects in React Why Math.max() Without Arguments Returns -Infinity How to Debounce and Throttle Callbacks in React Don't Confuse Function Expressions and Function Declarations in JavaScript How to Use ES Modules in Node.js Solving a Mystery Behavior of parseInt() in JavaScript How to Use Array Reduce Method in JavaScript 3 Ways to Merge Arrays in JavaScript A Guide to Jotai: the Minimalist React State Management Library The Difference Between Values and References in JavaScript How to Implement a Queue in JavaScript A Helpful Algorithm to Determine "this" value in JavaScript React useRef() Hook Explained in 3 Steps 7 Interview Questions on "this" keyword in JavaScript. Can You Answer Them? How to Greatly Enhance fetch() with the Decorator Pattern 7 Interview Questions on JavaScript Closures. Can You Answer Them? What's a Method in JavaScript? array.sort() Does Not Simply Sort Numbers in JavaScript How to Solve the Infinite Loop of React.useEffect() The New Array Method You'll Enjoy: array.at(index) What's the Difference between DOM Node and Element? Why Promises Are Faster Than setTimeout()? Everything About Callback Functions in JavaScript How React Updates State 5 Mistakes to Avoid When Using React Hooks 5 Best Practices to Write Quality JavaScript Variables Type checking in JavaScript: typeof and instanceof operators 3 Ways to Check if a Variable is Defined in JavaScript React Forms Tutorial: Access Input Values, Validate, Submit Forms Prototypal Inheritance in JavaScript How to Timeout a fetch() Request How to Learn JavaScript If You're a Beginner A Simple Explanation of React.useEffect() A Simple Explanation of JavaScript Iterators How to Use React Controlled Inputs Everything about null in JavaScript How to Use Fetch with async/await Getting Started with Arrow Functions in JavaScript An Interesting Explanation of async/await in JavaScript Front-end Architecture: Stable and Volatile Dependencies Is it Safe to Compare JavaScript Strings? How to Access Object's Keys, Values, and Entries in JavaScript What Actually is a String in JavaScript? 3 Ways to Shallow Clone Objects in JavaScript (w/ bonuses) Checking if an Array Contains a Value in JavaScript JavaScript Event Delegation: A Beginner's Guide How to Parse URL in JavaScript: hostname, pathname, query, hash 3 Ways to Detect an Array in JavaScript How to Get the Screen, Window, and Web Page Sizes in JavaScript 3 Ways to Check If an Object Has a Property/Key in JavaScript How to Compare Objects in JavaScript Object.is() vs Strict Equality Operator in JavaScript Own and Inherited Properties in JavaScript 5 Differences Between Arrow and Regular Functions How to Use Object Destructuring in JavaScript Your Guide to React.useCallback() 5 JavaScript Scope Gotchas
How to Use TypeScript with React Components
Dmitri Pavlutin · 2021-09-29 · via Dmitri Pavlutin Blog

In this post, I'm going to discuss why and how to use TypeScript to type React components.

You'll find how to annotate component props, mark a prop optional, and indicate the return type.

Table of Contents

  • 1. Why typing React components?
  • 2. Typing props
    • 2.1 Props validation
    • 2.2 children prop
    • 2.3 Optional props
  • 3. Return type
    • 3.1 Tip: enforce the return type
  • 4. Conclusion

1. Why typing React components?

TypeScript is useful if you're coding middle and bigger size web applications. Annotating variables, objects, and functions creates contracts between different parts of your application.

For example, let's say I am the author of a component that displays a formatted date on the screen.


interface FormatDateProps {

date: Date

}

function FormatDate({ date }: FormatDateProps): JSX.Element {

return <div>{date.toLocaleString()}</div>;

}


According to the FormatDateProps interface, the component FormatDate the value of date prop can only be an instance of Date. That is a constraint.

Why is this constraint important? Because the FormatDate component calls the method date.toLocaleString() on the date instance, and the date prop have to be a date instance. Otherwise, the component wouldn't work.

Then the user of the FormatDate component would have to satisfy the constraint, and provide date prop only with Date instances:


<FormatDate

date={new Date()}

/>


If the user forgets about the constraint, and for example provides a string "Sep 28 2021" to date prop:


// Type error:

// Type 'string' is not assignable to type 'Date'.

<FormatDate

date="Sep 28 2021"

/>


then TypeScript will show a type error.

That's great because the error is caught during development, without hiding in the codebase.

2. Typing props

In my opinion, the best benefit React takes from TypeScript is the props typing.

Typing a React component is usually a 2 steps process.

A) Define the interface that describes what props the component accepts using an object type. A good naming convention for the props interface is ComponentName + Props = ComponentNameProps

B) Then use the interface to annotate the props parameter inside the functional component function.

For example, let's annotate a component Message that accepts 2 props: text (a string) and important (a boolean):


interface MessageProps {

text: string;

important: boolean;

}

function Message({ text, important }: MessageProps) {

return (

<div>

{important ? 'Important message: ' : 'Regular message: '}

{text}

</div>

);

}


MessageProps is the interface that describes the props the component accepts: text prop as string, and important as boolean.

Now when rendering the component, you have to set the prop values according to the props type:


<Message

text="The form has been submitted!"

important={false}

/>


Basic Prop Types suggests types for different kinds of props. Use the list as an inspiration.

2.1 Props validation

Now if you happen to provide the component with the wrong set of props, or wrong value types, then TypeScript will warn you at compile time about the wrong prop value.

Usually, a bug is caught in one of the following phases — type checking, unit testing, integration testing, end-to-end tests, bug report from the user — and the earlier you catch the bug, the better!

If the Message component renders with an invalid prop value:


<Message

text="The form has been submitted!"

// Type error:

// Type 'number' is not assignable to type 'boolean'.

important={0}

/>


or without a prop:


<Message

// Type error:

// Property 'text' is missing in type '{ important: true; }'

// but required in type 'MessageProps'.

important={true}

/>


then TypeScript will warn about that.

2.2 children prop

children is a special prop in React components: it holds the content between the opening and closing tag when the component is rendered: <Component>children</Component>.

Mostly the content of the children prop is a JSX element, which can be typed using a special type JSX.Element (a type available globally in a React environment).

Let's slightly change the Message component to use a children prop:


interface MessageProps {

children: JSX.Element | JSX.Element[];

important: boolean;

}

function Message({ children, important }: MessageProps) {

return (

<div>

{important ? 'Important message: ' : 'Regular message: '}

{children}

</div>

);

}


Take a look at the children prop in the interface: it accepts a single element JSX.Element or an array of element JSX.Element[].

Now you can use an element as a child to indicate the message:


<Message important={false}>

<span>The form has been submitted!</span>

</Message>


or multiple children:


<Message important={false}>

<span>The form has been submitted!</span>

<span>Your request will be processed.</span>

</Message>


Challenge: how would you update the MessageProps interface to support also a simple string value as a child? Write your solution in a comment below!

2.3 Optional props

To make a prop optional in the props interface, mark it with a special symbol symbol ?.

For example, let's mark the important prop as optional:


interface MessageProps {

children: JSX.Element | JSX.Element[];

important?: boolean;

}

function Message({ children, important = false }: MessageProps) {

return (

<div>

{important ? 'Important message: ' : 'Regular message: '}

{children}

</div>

);

}


Inside MessageProps interface the important prop is marked with an ?important?: boolean — making the prop optional.

Inside the Message function I have also added a false default value to the important prop: { children, important = false }. That's going to be the default value in case if important prop is not indicated.

Now TypeScript allows you to skip the important prop:


<Message>

<span>The form has been submitted!</span>

</Message>


Of course, you can still use important if you'd like to:


<Message important={true}>

<span>The form has been submitted!</span>

</Message>


3. Return type

In the previous examples Message function doesn't indicate explicitly its return type. That's because TypeScript is smart and can infer the function's return type — JSX.Element:


// MessageReturnType is JSX.Element

type MessageReturnType = ReturnType<typeof Message>;


In the case of React functional components the return type is usually JSX.Element:


function Message({

children,

important = false

}: MessageProps): JSX.Element {

return (

<div>

{important ? 'Important message: ' : 'Regular message: '}

{children}

</div>

);

}


There are cases when the component might return nothing in certain conditions. If that's the case, just use a union JSX.Element | null as the return type:


interface ShowTextProps {

show: boolean;

text: string;

}

function ShowText({ show, text }: ShowTextProps): JSX.Element | null {

if (show) {

return <div>{text}</div>;

}

return null;

}


ShowText returns an element if show prop is true, otherwise returns null. That's why the ShowText function's return type is a union JSX.Element | null.

3.1 Tip: enforce the return type

My recommendation is to enforce each function to explicitly indicate the return type. Many silly mistakes and typos can be caught by doing so.

For example, if you have set accidently a newline between return and the returned expression, then the explicitly indicated return type would catch this problem:


function BrokenComponent(): JSX.Element {

// Type error:

// Type 'undefined' is not assignable to type 'Element'.

return

<div>Hello!</div>;

}


(Note: when there's a newline between the return keyword and an expression, then the function returns undefined rather than the expression.)

However, if there's no return type indicated, the incorrectly used return remains unnoticed by TypeScript (and by you!):


function BrokenComponent() {

return

<div>Hello!</div>;

}


Then good luck debugging!

4. Conclusion

React components can greatly benefit from TypeScript.

Typing components is especially useful to validate the component props. Usually, that's performed by defining an interface where each prop has its type.

Then, when the annotated component renders, TypeScript verifies if correct prop values were supplied.

On top of data validation, the types can be a great source of meta-information with clues of how the annotated function or variable works.