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

推荐订阅源

大猫的无限游戏
大猫的无限游戏
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

oida.dev | TypeScript, Rust

TypeScript's `erasableSyntaxOnly` Flag Unsafe for work Tokio: Macros Tokio: Channels Tokio: Getting Started Network Applications on the Tokio Stack Remake, Remodel, Reduce. The `never` type and error handling in TypeScript 5 Inconvenient Truths about TypeScript Refactoring in Rust: Introducing Traits Refactoring in Rust: Abstraction with the Newtype Pattern Announcing the TypeScript Cookbook TypeScript: Iterating over objects The road to universal JavaScript 10 years of oida.dev Rust: Tiny little traits The TypeScript converging point How not to learn TypeScript Getting started with Rust Introducing Slides and Coverage TypeScript: The humble function overload TypeScript + React: Children types are broken TypeScript: In defense of any Rust: Enums to wrap multiple errors Dissecting Deno Error handling in Rust TypeScript: Unexpected intersections Upgrading Node.js dependencies after a yarn audit TypeScript: Array.includes on narrow types TypeScript + React: Typing Generic forwardRefs shared, util, core: Schroedinger's module names Learning Rust and Go TypeScript: Narrow types in catch clauses TypeScript: Low maintenance types Tidy TypeScript: Name your generics Tidy TypeScript: Avoid traditional OOP patterns Tidy TypeScript: Prefer type aliases over interfaces Tidy TypeScript: Prefer union types over enums My new book: TypeScript in 50 Lessons Go Preact! ❤️ this in JavaScript and TypeScript TypeScript and ECMAScript Modules TypeScript + React: Component patterns TypeScript: Augmenting global and lib.dom.d.ts Vite with Preact and TypeScript TypeScript: Union to intersection type 11ty: Generate Twitter cards automatically Are large node module dependencies an issue? TypeScript: Variadic Tuple Types Preview TypeScript: Improving Object.keys Remake, Remodel. Part 4. TypeScript + React: Typing custom hooks with tuple types TypeScript: Assertion signatures and Object.defineProperty TypeScript: Check for object properties and narrow down type Boolean in JavaScript and TypeScript void in JavaScript and TypeScript Symbols in JavaScript and TypeScript Why I use TypeScript TypeScript + React: Extending JSX Elements TypeScript: Validate mapped types and const context TypeScript: Match the exact object shape TypeScript: The constructor interface pattern Streaming your Meetup - Part 4: Directing and Streaming with OBS Streaming your Meetup - Part 3: Speaker audio Streaming your Meetup - Part 2: Speaker video Streaming your Meetup - Part 1: Basics and Projector TypeScript and React Guide: Added a new styles chapter TypeScript and React Guide: Added a new render props chapter TypeScript and React: Styles and CSS TypeScript and React TypeScript and React Guide: Added a new prop types chapter TypeScript without TypeScript -- JSDoc superpowers TypeScript: Mapped types for type maps JAMStack vs serverless web apps The Unsung Benefits of JAMStack Sites TypeScript: Ambient modules for Webpack loaders My most favourite talks in 2018 TypeScript and React Guide: Added a new context chapter TypeScript: Built-in generic types TypeScript: Type predicates JSX is syntactic sugar TypeScript and React Guide: Added a new hooks chapter Getting your CfP application right FAQ on our Angular Connect Talk: Automating UI development TypeScript and Substitutability Debugging Node.js apps in TypeScript with Visual Studio Code From Medium: Deconfusing Pre- and Post-processing From Medium: PostCSS misconceptions Saving and scraping a website with Puppeteer Cutting the mustard - 2018 edition Wordpress as CMS for your JAMStack sites My most favourite podcast episodes in 2017 My most favourite talks in 2017 My most favourite books in 2017 The Best Request Is No Request, Revisited Not so hidden figures - Organizing ScriptConf My podcast journey to ScriptCast Grid layout, grid layout everywhere! #scriptconf and #devone Object streams in Node.js
TypeScript + React: Why I don't use React.FC
2020-07-30 · via oida.dev | TypeScript, Rust

Update: React types for version 18 changed a lot! If you encounter problems described in this article, make sure you update to the latest version!

In my recent article on TypeScript and React component patterns I’ve stated that I don’t use the built-in type React.FC<> but rather be explicit with typing children. I didn’t state why, and it sparked some interest. That’s why I want to elaborate a little bit.

Please note that this is just an opinion, not a suggestion or anything else. If you like to use React.FC and it works for you, please continue to do so! That’s totally fine and sometimes I do so as well! And let’s be serious: There are different problems out there that need discussion and are more enough a reason to get angry. So don’t waste your time getting too emotional about code styles. But if you like to get new ideas, please continue!

Hat tip to Martin Hochel who wrote about not using React.FC ages ago in his piece on component patterns.

What’s React.FC<>? #

In React you have two ways of defining components.

  1. Writing a class and extending from Component
  2. Writing a function and returning JSX

Since React was not written in TypeScript, the community provides types with the @types/react package. In there is a generic type called FC that allows us to type our function components, like this:

import React, { FC } from "react";

type GreetingProps = {
name: string;
}

const Greeting:FC<GreetingProps> = ({ name }) => {
// name is string!
return <h1>Hello {name}</h1>
};

Personally, I think the type is excellent as it covers everything that function components can be and allow in just a couple lines of code:

interface FunctionComponent<P = {}> {
(props: PropsWithChildren<P>, context?: any)
: ReactElement<any, any> | null;
propTypes?: WeakValidationMap<P>;
contextTypes?: ValidationMap<any>;
defaultProps?: Partial<P>;
displayName?: string;
}

See GitHub for reference. Still, I’m not using it. So why?

1. You type a function, not its arguments #

React.FC types a function. That’s in its name, function component. Function types are really hard to apply to regularly named functions. Where do you put the function type in code like this:

function Greeting({ name }) {
return <h1>Hello {name}</h1>
}

You can use an anonymous function and assign it to a const/variable:

const Greeting:FC<GreetingProps> = function({ name }) {
return <h1>Hello {name}</h1>
}

Or use arrow functions like in the example above. But we totally exclude simple, regular functions.

If we don’t type functions, but rather its properties, we can use any form of functions to achieve our goal:

// ✅
function Greeting({ name }: GreetingProps) {
return <h1>Hello {name}</h1>
}

And yes, even in times of arrow functions and transpilation, writing regular, old, boring, working, and simple named functions is totally valid! And nice!

2. FC<> always imply children #

This is also an argument Martin makes in his original article. Typing with React.FC<> opens your components for children. For example:

export const Greeting:FC<GreetingProps> = ({ name }) => {
// name is string!
return <h1>Hello {name}</h1>
};

// use it in the app
const App = () => <>
<Greeting name="Stefan">
<span>{"I can set this element but it doesn't do anything"}</span>
</Greeting>
</>

If I use simple props instead of FC, TypeScript tells me that I pass along children even if my component tells me that I shouldn’t.

function Greeting({ name }: GreetingProps) {
return <h1>Hello {name}</h1>
}
const App = () => <>
<Greeting name="Stefan">
{/* The next line throws errors at me! 💥*/}
<span>{"I can set this element but it doesn't do anything"}</span>
</Greeting>
</>

And to be fair, handling children types is not TypeScript’s strength. But getting at least the information that there shouldn’t be children in the first place helps.

Be explicit. State that your component is using children when it really needs to! I wrote a WithChildren helper type for that.

type WithChildren<T = {}> = 
T & { children?: React.ReactNode };

type CardProps = WithChildren<{
title: string
}>

function Card({ title, children }: CardProps) {
return <>
<h1>{ title }</h1>
{children}
</>
}

Works just as well and has one big benefit…

3. Easier to move to Preact #

If you are not using Preact, you should! It does the same thing, the preact/compat package makes sure you are compatible with the React ecosystem. You can save up to 100 KB of production size and you are using an independent library!

Recently I started moving all my React projects to Preact. Preact is written in TypeScript (with JSDoc annotations), so you get all the good typing information with an installation of Preact. Everything from @types/react isn’t compatible anymore. Since React.FC is tacked on, you would need to refactor all your existing code to something that, well, would mimic simple functions with typed props anyways.

// The Preact version
type WithChildren<T = {}> =
T & { children?: VNode };

4. React.FC<> breaks defaultProps #

defaultProps is a relic from class-based React where you were able to set default values to your props. With function components, this is now basic JavaScript as you can see here. Still, you might get into some situations where setting defaultProps (or other static properties) is still necessary.

Since version 3.1, TypeScript has a mechanism to understand defaultProps and can set default values based on the values you set. However, React.FC types defaultProps, and thus breaks the connection to use them as default values. So this one breaks:

export const Greeting:FC<GreetingProps> = ({ name }) => {
// name is string!
return <h1>Hello {name}</h1>
};

Greeting.defaultProps = {
name: "World"
};

const App = () => <>
{/* Big boom 💥*/}
<Greeting />
</>

Not using FC but just a function (regular, named, anonymous, arrow, whatever) with typed props works!

export const Greeting = ({ name }: GreetingProps) => {
// name is string!
return <h1>Hello {name}</h1>
};

Greeting.defaultProps = {
name: "World"
};

const App = () => <>
{/* Yes! ✅ */}
<Greeting />
</>

5. Future-proof #

Remember when everybody called function components stateless function components. Yeah, with the introduction of hooks we suddenly had lots of state in our function components. This reflected in the SFC type that is now FC, and who knows, could change in the future as well. Typing your arguments (props), and not the function itself, keeps you away from changing function types.

Bottom line #

So those are a couple of arguments I have to not use React.FC. That being said, I think it’s totally legit and fine to use React.FC if it’s good and well for your workflow. I’ve been using it a lot in the past and well, it works! So please don’t feel pushed to change your coding style if you can run with it.

But maybe you see that typing props can be much simpler, much closer to JavaScript. And maybe this suits your coding style more!

Related Articles