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

推荐订阅源

Vercel News
Vercel News
O
OpenAI News
Engineering at Meta
Engineering at Meta
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
月光博客
月光博客
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
WordPress大学
WordPress大学
宝玉的分享
宝玉的分享
GbyAI
GbyAI
T
The Blog of Author Tim Ferriss
Google DeepMind News
Google DeepMind News
B
Blog RSS Feed
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
云风的 BLOG
云风的 BLOG
罗磊的独立博客
S
SegmentFault 最新的问题
The Register - Security
The Register - Security
Hugging Face - Blog
Hugging Face - Blog
D
DataBreaches.Net
U
Unit 42
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
B
Blog
阮一峰的网络日志
阮一峰的网络日志
P
Proofpoint News Feed
雷峰网
雷峰网
V
Visual Studio Blog
小众软件
小众软件
aimingoo的专栏
aimingoo的专栏
N
Netflix TechBlog - Medium
酷 壳 – CoolShell
酷 壳 – CoolShell
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Y
Y Combinator Blog
博客园 - 【当耐特】
G
Google Developers Blog
L
LangChain Blog
Stack Overflow Blog
Stack Overflow Blog
I
InfoQ
Martin Fowler
Martin Fowler
F
Fortinet All Blogs
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
The Cloudflare Blog
AI
AI
Google Online Security Blog
Google Online Security Blog
Hacker News - Newest:
Hacker News - Newest: "LLM"
博客园 - Franky
Blog — PlanetScale
Blog — PlanetScale
Webroot Blog
Webroot Blog
PCI Perspectives
PCI Perspectives
爱范儿
爱范儿
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org

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