【问题标题】:How to add defaultProps to a generic functional component with component injection in TypeScript?如何在 TypeScript 中使用组件注入将 defaultProps 添加到通用功能组件?
【发布时间】:2020-01-27 03:52:24
【问题描述】:

我有一个功能组件Button,它使用一个道具as 来注入一个HTML 元素或另一个组件。我想将as 属性默认为react-routerLink 组件。这将使Linkto 道具成为Button 的强制道具。所以,我写<Button>Press me!</Button>的时候应该会报错,但是编译器没有报错。

我正在使用 typescript v3.5.3,在 tsconfig.json 中有以下设置:

{
  "compilerOptions": {

    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noImplicitThis": true,
    "strictFunctionTypes": true,
    "strictBindCallApply": true,
    "alwaysStrict": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true
  }
}

这是我目前的情况(简化),Link 作为as es6 样式的默认值:

import React from 'react'
import { Link } from 'react-router-dom'

interface ButtonProps {
  children?: string
}

type ElementInjector<T extends React.ElementType> = {
  as: T
} & React.ComponentPropsWithoutRef<T>

export const Button = <T extends React.ElementType>({
  as: Tag = Link,
  ...props
}: ButtonProps & ElementInjector<T>) => {
  return <Tag {...props} />
}

因此,鉴于上述情况,这是结果和期望:

<Button>Button</Button>            // error   - asking for `as` not `to`
<Button as={Link}>Button</Button>  // error   - ok
<Button to="/">Button</Button>     // error   - asking for `as`
<Button as="a">Button</Button>     // success - ok

如何让第一个失败?

解决以下问题也很酷。与defaultProps 无关,但与通用方法有关。

<Button as="a" to="/">Button</Button>      // success - error expected
<Button<'a'> as="a" to="/">Button</Button> // error   - ok

Example to play with

【问题讨论】:

    标签: reactjs typescript typescript-generics


    【解决方案1】:

    在向组件推断类型参数时不会考虑参数默认值。由于没有其他地方可以取用T,它将默认为unknown。解决方案是为T 添加一个默认类型

    
    export const Button = <T extends React.ElementType = typeof Link>({
        tag: Tag = Link,
        ...props
      }: ButtonProps & ElementInjector<T>) => {
        return <Tag {...props} />
      }
    
    let x = <Button>Button</Button>                      // error expected
    let x1 = <Button tag={Link}>Button</Button>          // error   - ok
    let x2 = <Button to="/">Button</Button>              // success - ok
    let x3 = <Button tag="a">Button</Button>             // success - ok
    

    关于你的第二个问题,它类似于this 问题,但我无法让它工作,如果我有更新会发布。

    【讨论】:

    猜你喜欢
    • 2019-03-28
    • 2016-07-22
    • 2021-04-06
    • 2017-12-31
    • 1970-01-01
    • 2021-01-17
    • 2021-03-08
    • 2021-06-02
    • 1970-01-01
    相关资源
    最近更新 更多