Typescript接口-可使;“一个或另一个”;所需的属性?
可能是一个奇怪的问题,但我很好奇是否有可能在需要一个属性或另一个属性的地方创建一个接口 所以,举个例子Typescript接口-可使;“一个或另一个”;所需的属性?,typescript,Typescript,可能是一个奇怪的问题,但我很好奇是否有可能在需要一个属性或另一个属性的地方创建一个接口 所以,举个例子 interface Message { text: string; attachment: Attachment; timestamp?: number; // ...etc } interface Attachment {...} 在上述情况下,我希望确保文本或附件存在 希望这是有道理的 提前谢谢 编辑:我现在就是这样做的。我觉得有点冗长(为slack键
interface Message {
text: string;
attachment: Attachment;
timestamp?: number;
// ...etc
}
interface Attachment {...}
在上述情况下,我希望确保文本
或附件
存在
希望这是有道理的
提前谢谢
编辑:我现在就是这样做的。我觉得有点冗长(为slack键入botkit)
可以使用联合类型执行此操作:
interface MessageBasics {
timestamp?: number;
/* more general properties here */
}
interface MessageWithText extends MessageBasics {
text: string;
}
interface MessageWithAttachment extends MessageBasics {
attachment: Attachment;
}
type Message = MessageWithText | MessageWithAttachment;
如果您想同时允许文本和附件,您可以编写
type Message = MessageWithText | MessageWithAttachment | (MessageWithText & MessageWithAttachment);
谢谢@ryan cavanaugh,这让我找到了正确的方向 我有一个类似的例子,但接下来是数组类型。对语法有点纠结,所以我把它放在这里供以后参考:
接口基本规则{
optionalProp?:数字
}
接口规则扩展了BaseRule{
requiredPropA:字符串
}
接口RuleB扩展了BaseRule{
requiredPropB:字符串
}
类型SpecialRules=Array
//或
键入特殊规则=(规则A |规则B)[]
//或者(在我参加的严格的linted项目中):
特殊规则类型=规则A |规则B
类型SpecialRules=SpecialRule[]
更新:
请注意,稍后在代码中使用声明的变量时,仍可能会收到警告。然后可以使用(变量作为类型)
语法。
例如:
const myRules:SpecialRules=[
{
可选项目:123,
requiredPropA:'此对象属于RuleA类型'
},
{
requiredPropB:'此对象的类型为RuleB'
}
]
myRules.map((规则)=>{
如果((规则A.requiredPropA){
//做事
}否则{
//做其他事情
}
})
您可以为所需的条件创建几个接口,并以如下类型连接它们:
interface SolidPart {
name: string;
surname: string;
action: 'add' | 'edit' | 'delete';
id?: number;
}
interface WithId {
action: 'edit' | 'delete';
id: number;
}
interface WithoutId {
action: 'add';
id?: number;
}
export type Entity = SolidPart & (WithId | WithoutId);
const item: Entity = { // valid
name: 'John',
surname: 'Doe',
action: 'add'
}
const item: Entity = { // not valid, id required for action === 'edit'
name: 'John',
surname: 'Doe',
action: 'edit'
}
你可以使用一些很酷的Typescript选项 你的问题是:在“文本”或附件存在的地方创建一个接口。你可以这样做:
interface AllMessageProperties {
text: string,
attachement: string,
}
type Message = Omit<AllMessageProperties, 'text'> | Omit<AllMessageProperties, 'attachement'>;
const messageWithText : Message = {
text: 'some text'
}
const messageWithAttachement : Message = {
attachement: 'path-to/attachment'
}
const messageWithTextAndAttachement : Message = {
text: 'some text',
attachement: 'path-to/attachment'
}
// results in Typescript error
const messageWithOutTextOrAttachement : Message = {
}
接口AllMessageProperties{
文本:字符串,
附件:细绳,
}
类型消息=省略|省略;
const messageWithText:Message={
文本:“一些文本”
}
const messageWithAttachement:Message={
附件:“指向/附件的路径”
}
const messageWithTextAndAttachement:Message={
文本:“一些文本”,
附件:“指向/附件的路径”
}
//导致键入脚本错误
const messagewithout text附件:Message={
}
好的,经过一段时间的反复试验和谷歌搜索,我发现答案并没有像我的用例预期的那样有效。所以,如果其他人也有同样的问题,我想我会分享我是如何让它工作的。我的界面是这样的:
export interface MainProps {
prop1?: string;
prop2?: string;
prop3: string;
}
我想要的是一个类型定义,它可以说我们既不能定义prop1也不能定义prop2。我们可以定义prop1,但不能定义prop2。最后定义了prop2,但没有定义prop1。以下是我发现的解决方案
interface MainBase {
prop3: string;
}
interface MainWithProp1 {
prop1: string;
}
interface MainWithProp2 {
prop2: string;
}
export type MainProps = MainBase | (MainBase & MainWithProp1) | (MainBase & MainWithProp2);
这工作得很好,但有一个警告是,当我试图在另一个文件中引用prop1或prop2时,我一直得到一个属性不存在的错误。以下是我如何绕过这一点的:
import {MainProps} from 'location/MainProps';
const namedFunction = (props: MainProps) => {
if('prop1' in props){
doSomethingWith(props.prop1);
} else if ('prop2' in props){
doSomethingWith(props.prop2);
} else {
// neither prop1 nor prop2 are defined
}
}
我只是想和大家分享一下,因为如果我遇到了那么一点点奇怪的事情,那么其他人可能也是 如果您真正追求的是“一个属性或另一个属性”,而不是两个属性,则可以在扩展类型中使用never
:
interface MessageBasics{
时间戳?:数字;
/*这里有更一般的属性*/
}
MessageWithText接口扩展了MessageBasics{
文本:字符串;
附件?:从未;
}
接口MessageWithAttachment扩展了MessageBasics{
文本?:从不;
附件:字符串;
}
键入Message=MessageWithText | MessageWithAttachment;
//我在为我的案例寻找答案时偶然发现了这条线索(propA、propB或两者都没有)。Ryan Fujiwara的回答几乎成功了,但我失去了一些支票
我的解决方案:
interface ComponentBase {
baseProp: string;
}
interface ComponentWithPropA extends Base {
propA: string;
propB?: never;
}
interface ComponentWithPropB extends Base {
propB: string;
propA?: never;
}
interface ComponentWithoutProps extends Base {
propA?: never;
propB?: never;
}
type ComponentProps = ComponentWithPropA | ComponentWithPropB | ComponentWithoutProps;
此解决方案使所有检查保持原样。也许有人会发现这一点很有用:)您可以通过@robstarbuck solution创建以下类型来深入了解:
type Only<T, U> = {
[P in keyof T]: T[P];
} & {
[P in keyof U]?: never;
};
type Either<T, U> = Only<T, U> | Only<U, T>;
使用此解决方案,您可以轻松地在MessageWithText
或MessageWithAttachment
类型中添加更多字段,而无需将其排除在另一个类型中。但这将不允许他拥有带有文本和附件的邮件谢谢您的回复!我现在就是这样做的。我在上面的问题中补充了这一点。我不确定是否有更干净的方法来解决这个问题。@Roberto但这并不排除!这两个都接受。答案不起作用,键入Message
接受{text:'a',attachment:'b'}
最后一个`|(MessageWithText&MessageWithAttachment)`不起任何作用-没有它,它的行为完全相同。只是一个简短的提示,让您知道有一个类型安全,intellisense是一种编写.map()
代码的友好方式。在
操作符中使用带有的类型防护装置。TypeScript将进行适当的类型推断,等等。因此,如果规则中的('requiredPropA'){/*在这里,TS知道规则的类型是*/}
@golopot,在阅读您的注释后,这应该是您想要的解决方案。这是最好的一个,它会在分配两个属性时发出尖叫,与前面的回答不同,此回答显示了如何自动执行此“XOR”类型:查看我建议的解决方案。是否有方法使用省略使此文本XOR附件?是否有方法使其与参数分解兼容?如果我尝试这样做,就会出现TS错误:有什么方法可以使其与参数分解兼容?如果我尝试函数myFunc({text,attachment}:Message){}
type Only<T, U> = {
[P in keyof T]: T[P];
} & {
[P in keyof U]?: never;
};
type Either<T, U> = Only<T, U> | Only<U, T>;
interface MessageBasics {
timestamp?: number;
/* more general properties here */
}
interface MessageWithText extends MessageBasics {
text: string;
}
interface MessageWithAttachment extends MessageBasics {
attachment: string;
}
type Message = Either<MessageWithText, MessageWithAttachment>;