TypeScript X JSX = TSX

如何使用TSX

  • Webpack—— create-react-app / VueCli
  • Vite—— template + plugin(plugin-vue-jsx)
  • Next.js / Remix.js / Fresh.js
  • 其他

标签与断言之冲突

  1. const header = <h1>hi</h1>
  2. const a = 1 as unknown
  3. const b = a as number
  4. // 有歧义的断言 tsx下报错 ts下可以,tsx下不要使用
  5. const c = <number>a // error
  6. export {header}

TypeScript x JSX = TSX - 图1

在JSX中,只能用as断言。

JSX/TSX的本质

  1. const header = <h1 name="frank">hi</h1>
  2. // 编译 后 伪代码 其实还是在写JS/TS,那就是还有类型
  3. import {create} from 'react_or_vue/jsx'
  4. const header = create('hi', { name: 'fank' }, 'hi')

TypeScript x JSX = TSX - 图2

TypeScript x JSX = TSX - 图3

JSX的本质就是编译后变成函数,并且是可以配置的。

浏览器的标签都要在全局声明中声明过。创建标签对应的类型是由JSX.Element命名的。

函数组件

  1. const Header = (x: { level: number }, context: unknown) => {
  2. console.log(x, context)
  3. return <h1 name="frank">hi</h1>
  4. }
  5. const App = <Header level={1} />

类组件

接受类型是通过props来接受的。

  1. class ClassHeader {
  2. props: {
  3. level: number
  4. }
  5. constructor(props: { level: number }) {
  6. this.props = props
  7. }
  8. render() {
  9. return <h1>level: { this.props.level }</h1>
  10. }
  11. }
  12. const App2 = <ClassHeader level={1}/>

组件共有属性

  1. // 函数组件或类组件需要的共有属性
  2. interface IntrinsicAttributes {
  3. key: string
  4. }
  5. // class属性需要的共有属性
  6. interface IntrinsicClassAttributes<T> {
  7. // Ref 相当于拥有一个 current 对象
  8. ref: {
  9. current: T | null
  10. }
  11. }

JSX如何把内容变成props的属性

需要在全局声明中声明JSX元素的Children属性。React内是Children,而Vue内相当变成了插槽slot

  1. interface ElementChildrenAttributes {
  2. children: {}
  3. }

React/Vue项目中声明jsx类型的地方

react项目使用jsx,声明了jsx类型的地方

TypeScript x JSX = TSX - 图4

vue项目使用jsx,声明jsx类型的地方

TypeScript x JSX = TSX - 图5

JSX.Element v.s. ReactElement v.s. ReactNode

ReactNode 为 react节点

TypeScript x JSX = TSX - 图6

jsx继承了reactElement

TypeScript x JSX = TSX - 图7

ReactFragment是一个语法糖,类型声明里面为迭代器,[]数组是最简单的迭代器。

ReactProtal是传送门。

React事件处理函数的类型

可以先点击原有的方法去查找类型,然后再去输入。

  1. const App = () => {
  2. const onClick: MouseEventHandler<HTMLInputElement> | undefined = (e) => {
  3. console.log((e.target as HTMLInputElement).value)
  4. }
  5. const onChange: ChangeEventHanler<HTMLInputElement> | undefined = (e) => {
  6. console.log(e.target.value)
  7. }
  8. // onchange 触发时机是在失去焦点
  9. // oninput 触发时机是在输入时
  10. // oncompositionstart 开始输入
  11. // oncompositionend 结束输入
  12. return (
  13. <input onClick={onClick} onChange={onChange}/>
  14. )
  15. }

是否可以指定children的类型?

不完全可以。

  1. type BProps = {}
  2. const B: React.FC<BProps> = (props) => <div>B组件</div>
  3. type CProps = {}
  4. const C: React.FC<CProps> = (props) => <div>C组件</div>
  5. type X = ReturnType<typeof C>
  6. type AProps = {
  7. children?: ReturnType<typeof B>
  8. }
  9. const A: React.FC<AProps> = (props) => {
  10. if(props.children?.type !== B){
  11. throw new Error('children必须是B组件')
  12. }
  13. return <div>{props.children}</div>
  14. }
  15. const App = () => {
  16. return (
  17. <A>
  18. <C/>
  19. </A>
  20. )
  21. }

参考文章如下所示。

react 指定props.children为某个组件 - SegmentFault 思否

React泛型组件是什么?

即能接受泛型的组件。

React 泛型组件是什么?

思考题:Vue + TSX 有泛型组件吗?为什么?

答案是没有,vue的组件是一个对象,不是函数做不到