【问题标题】:How to change property requirement dynamically如何动态更改属性要求
【发布时间】:2018-06-27 09:50:36
【问题描述】:

我有一个小部件,我们称之为MyText。它有 2 个可选的 props,xy。如果在道具中定义了y,我想强制x,反之亦然。

这里是 MyText

interface Props {
  x?: number,
  y?: number,
}

class MyText extends React.Component<Props> {
  render() {
    return (
      <View>
        <Text>X is : {this.props.x}</Text>
        <Text>Y is : {this.props.y}</Text>
      </View>
    );
  }
}

当我调用它时,我想像这样输出

 <MyText x={1} /> // Error: Should say missing y
 <MyText y={4} /> // Error: Should say missing x
 <MyText x={1} y={4}/> // No error
 <MyText/> // No error

是否可以使用 TypeScript

当前解决方案:

使用单个对象存储xy,并使其可选。

interface XY{
  x : number,
  y : number
}

interface Props {
  xy?: XY,
}

class MyText extends React.Component<Props> {
  render() {
    return (
      <View>
        <Text>X is : {this.props.xy.x}</Text>
        <Text>Y is : {this.props.xy.y}</Text>
      </View>
    );
  }
}

然后这样称呼它

<MyText xy={{x:1,y:2}} />

我想知道是否有比这更好的方法,例如内置关键字或其他使一个属性依赖于另一个属性的技术。

【问题讨论】:

    标签: reactjs typescript react-native


    【解决方案1】:

    一种天真的方法是指定Props 是具有强制属性的interafec 和空的{ x: number; y : number } | {} 之间的联合类型。这样做的问题是额外属性的检查不能完全按预期工作:

    let p : { x: number; y : number } | {} = { x: 0 } // Compiler says ok, even though the object has more properties then `{}` and does not satisfy  { x: number; y : number }
    

    为了解决这个问题,我们可以使用联合,其中第一个成员同时具有 xy 强制,联合的第二个成员具有可选属性和很少用于的类型属性并且很难指定为文字。最好的候选人是never

    let p1 : { x: number; y : number } | { x?: never; y?: never } = { x: 0, y: 0 } // ok 
    let p2 : { x: number; y : number } | { x?: never; y?: never } = { x: 0 }  // invalid
    let p3 : { x: number; y : number } | { x?: never; y?: never } = { }  // ok
    

    将此应用于您的案例,我们得到:

    type Props = {
        x: number,
        y: number,
    } | {
        x?: never,
        y?: never,
    }
    
    class MyText extends React.Component<Props> {
        render() {
            return null;
        }
    }
    
    let s1 = <MyText x={1} /> // Error: Says x is not assignable to never, not ideal but you get used to it
    let s2 =  <MyText y={4} /> // Error: Says y is not assignable to y
    let s3 =  <MyText x={1} y={4}/> // No error
    let s4 =  <MyText/> // No error
    

    获得更友好的错误消息的一种方法是使用带有更友好消息的字符串文字类型。这确实会带来风险,即有人会指定错误消息的值,这会使编译器感到高兴,但希望您的团队成员会发现x = 'ERROR: y is missing, you must specify y' 没有多大意义:

    type Props = {
        x: number,
        y: number,
    } | {
        x?: 'ERROR: y is missing, you must specify y',
        y?: 'ERROR: x is missing, you must specify x',
    }
    
    let s1 = <MyText x={1} /> // Type 'number' is not assignable to type '"ERROR: y is missing, you must specify y" | undefined'.
    let s2 =  <MyText y={4} /> // Type 'number' is not assignable to type '"ERROR: x is missing, you must specify x" | undefined'
    let sSilly =  <MyText y='ERROR: x is missing, you must specify x' /> // valid but ilogical enough to not worry about it
    let s3 =  <MyText x={1} y={4}/> // No error
    let s4 =  <MyText/> // No error
    

    【讨论】:

    • 感谢@Titian 的回复 :)
    • @theapache64 添加了一个错误稍微友好的版本,希望对您有所帮助,祝您好运:)
    • 谢谢 :),您如何看待我在问题中指定的当前解决方案?它是否有任何性能问题,因为xy 是在render 方法中传递的?
    • @theapache64 我不太担心它的性能,似乎也是一个不错的解决方案:)
    猜你喜欢
    • 2015-07-16
    • 2015-03-10
    • 2019-08-11
    • 2011-05-03
    • 2021-01-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多