我有一个小部件,我们称之为MyText
。它有2个可选道具x
和y
。如果在道具中定义了x
,我想使y
为强制性,反之亦然。
这里是我的文字
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
?
当前解决方案:
使用单个对象存储x
和y
,并将其设置为可选。
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}} />
我想知道是否有比这更好的方法,例如内置关键字或其他使一个属性依赖于另一个属性的技术。
答案 0 :(得分:3)
天真的方法是指定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 }
要解决此问题,我们可以使用一个联合,其中第一个成员同时具有x
和y
强制,而联合的第二个成员同时具有可选属性和类型为既很少用于属性,也很难指定为文字。最好的选择是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