这可能是一个奇怪的问题,但我很好奇是否有可能创建一个需要其中一个属性的接口。
所以,例如……
interface Message {
text: string;
attachment: Attachment;
timestamp?: number;
// ...etc
}
interface Attachment {...}
在上面的情况下,我想确保文本或附件都存在。
我现在就是这么做的。我觉得它有点啰嗦(为slack输入botkit)。
interface Message {
type?: string;
channel?: string;
user?: string;
text?: string;
attachments?: Slack.Attachment[];
ts?: string;
team?: string;
event?: string;
match?: [string, {index: number}, {input: string}];
}
interface AttachmentMessageNoContext extends Message {
channel: string;
attachments: Slack.Attachment[];
}
interface TextMessageNoContext extends Message {
channel: string;
text: string;
}
谢谢@ryan-cavanaugh,让我找到了正确的方向。
我有一个类似的情况,但是是数组类型。在语法上有点困难,所以我把它放在这里供以后参考:
interface BaseRule {
optionalProp?: number
}
interface RuleA extends BaseRule {
requiredPropA: string
}
interface RuleB extends BaseRule {
requiredPropB: string
}
type SpecialRules = Array<RuleA | RuleB>
// or
type SpecialRules = (RuleA | RuleB)[]
// or (in the strict linted project I'm in):
type SpecialRule = RuleA | RuleB
type SpecialRules = SpecialRule[]
更新:
请注意,稍后在代码中使用声明的变量时,可能仍然会收到警告。然后可以使用(变量作为类型)语法。
例子:
const myRules: SpecialRules = [
{
optionalProp: 123,
requiredPropA: 'This object is of type RuleA'
},
{
requiredPropB: 'This object is of type RuleB'
}
]
myRules.map((rule) => {
if ((rule as RuleA).requiredPropA) {
// do stuff
} else {
// do other stuff
}
})
有一些很酷的Typescript选项,你可以使用https://www.typescriptlang.org/docs/handbook/utility-types.html#omittk
你的问题是:创造一个既存在“文本”又存在附件的界面。你可以这样做:
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 = {
}
到目前为止还没有人提到过,但我认为,无论谁偶然看到这一页,都可以考虑使用受歧视的工会。如果我正确理解OP代码的意图,那么它可能会像这样转换。
interface Attachment {}
interface MessageBase {
type?: string;
user?: string;
ts?: string;
team?: string;
event?: string;
match?: [string, {index: number}, {input: string}];
}
interface AttachmentMessageNoContext extends MessageBase {
kind: 'withAttachments',
channel: string;
attachments: Attachment[];
}
interface TextMessageNoContext extends MessageBase {
kind: 'justText',
channel: string;
text: string;
}
type Message = TextMessageNoContext | AttachmentMessageNoContext
const textMessage: Message = {
kind: 'justText',
channel: 'foo',
text: "whats up???"
}
const messageWithAttachment: Message = {
kind: 'withAttachments',
channel: 'foo',
attachments: []
}
现在Message接口需要附件或文本,这取决于kind属性。
我进一步压缩了@Voskanyan David的解决方案,得到了我个人认为非常简洁的解决方案:
你仍然需要在某个地方定义Only<>和Either<>
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>
之后,可以在没有任何中间接口/类型的情况下定义它:
type Message {
type?: string;
channel?: string;
user?: string;
// ...etc
} & Either<{message: string}, {attachment: Attachment}>