TypeScript 和 JSX 第一部分 - 什么是 JSX?
自 2019 年起,TypeScript 已成为 Web 开发者的首选编程语言,并且越来越受欢迎。在本系列文章中,我们将探讨 TypeScript 编译器如何处理 JSX,以及它如何与最流行的 JSX 使用框架 React 进行交互。
首先,JSX 是如何工作的?以下是一些 JSX 的示例:
// a native 'span' element with some text children
const mySpan = <span>Hello world!</span>
// a custom 'CustomSpan' element with some props and some children
const myCustomSpan = (
<CustomSpan
key='_myspan'
bold
color="red"
>
Hello world!
</CustomSpan>
)
// a native, self-closing 'input' element without any children
const myInput = <input />
// a custom 'Container' element with multiple children
const myWidget = (
<Container>
I am a widget
<Button>Click me!</Button>
</Container>
)
JSX 是 JavaScript 的一种非 ECMAScript 兼容语法,TypeScript 通过编译器标志支持它--jsx
。如果你是 React 开发者,那么 JSX 实际上只是一种语法糖,它会被编译成这样(如果你使用 TypeScript 编译器):
// a native 'span' element with some text children
const mySpan = React.createElement('span', null, 'Hello world!')
// a custom 'CustomSpan' element with some props and some children
const myCustomSpan = React.createElement(
CustomSpan,
{ key: 'myspan', bold: true, color: 'red' },
'Hello world!'
)
// a native, self-closing 'input' element without any children
const myInput = React.createElement('input', null)
// a custom 'Container' element with multiple children
const myWidget = React.createElement(
Container,
{ onClick: console.log },
'I am a widget',
React.createElement(Button, null, 'Click me!')
)
这已经有很多内容需要剖析了;让我们注意一下这个转变中的一些有趣的事情:
- 整个JSX 表达式变成了对名为 的函数的调用
React.createElement
。这就是为什么import React from 'react'
如果你使用 JSX 就总是需要这样做,即使这个变量React
在你的代码中从未真正使用过! - JSX 表达式中的标签名称被移动到函数调用的第一个参数。
- 如果标签名称以大写字母开头,或者(示例中未显示)它是属性访问(如
<foo.bar />
),则保持原样。 - 如果标签名称是单个小写单词,则将其转换为字符串文字(
input -> 'input'
)
- 如果标签名称以大写字母开头,或者(示例中未显示)它是属性访问(如
- 所有的 props (或者说是属性,在抽象语法树中如此称呼)都会被转换成一个对象,并移动到函数调用的第二个参数,需要注意一些特殊的语法:
- 如果没有传入任何 props,那么值就不是一个空对象,也不是
undefined
,而只是null
。 - 简写属性语法(如
bold
中的 propmyInput
)被转换为具有值 的对象属性true
。 - 尽管 React 将
key
和ref
视为特殊属性,但它们仍然(就语法而言)是转换中的常规属性。 - 对象属性的顺序与它们在 JSX 表达式中作为属性出现的顺序相同。
- 如果没有传入任何 props,那么值就不是一个空对象,也不是
- 如果需要的话,子项会被转换(如果它们也是 JSX),并按照它们出现的顺序放置,作为函数调用的其余参数。
- React 有一种特殊的行为,即 JSX 中的单个子元素在 中仅显示为该节点
props.children
,但在 中则显示为包含多个子元素的节点数组。语法或规范并未强制要求这样做。实际上,Preact 始终会将子元素包装在一个数组中,无论有多少个,因此这部分属于实现细节。
- React 有一种特殊的行为,即 JSX 中的单个子元素在 中仅显示为该节点
这就是 JSX 语法的全部内容;归根结底,它只是用于构建嵌套函数调用的语法糖,不会伤到你的大脑。
那么,为什么编译器知道应该使用React.createElement
函数而不是其他东西呢?其实你可以把它改成任何你想要的!你只需要在文件顶部添加注释或设置编译器标志:
/* @jsx myCustomJsxFactory.produce */
// your code here
// tsconfig.json
{
"compilerOptions": { "jsxFactory": "myCustomJsxFactory.produce" }
}
它们做同样的事情,结果只是默认值是React.createElement
。
在本系列的下一篇文章中,我们将通过构建我们自己的 JSX 工厂函数的工作示例来探索 TypeScript 如何知道如何根据 JSX 语法进行类型检查。
文章来源:https://dev.to/ferdaber/typescript-and-jsx-part-i---what-is-jsx-3g8b