繁体   English   中英

在同一接口中基于另一个属性定义属性的类型

[英]Define type of a property based on another property in the same interface

我有一个非常简单的界面

type MessageType = 'name' | 'age';
type MessageData = string | number 

interface Message {
    type: MessageType;
    data: MessageData;
}

我现在想要实现的是,当创建一个对象来实现类型为name Message时,要让TypeScript知道,该data必须为string类型,如果不是,则将其lint。

const message: Message = {
    type: 'name',
    data: 'Michael'
}

我通过这种实现实现了这一点

type MessageType = 'name' | 'age';
type MessageData<T extends MessageType> = T extends 'name' ? string : number;

interface Message<T extends MessageType> {
    type: T;
    data: MessageData<T>;
}

const message: Message<'name'> = {
    type: 'name',
    data: 'Michael'
}

但是,我不想提供MessageType ,而是让Message使用我传递给type的值。

您可以在这里尝试这种情况

SOULTION

借助jcalz找到了高度可扩展的解决方案:

interface MessageDataMap {
    name: string;
    age: number;
    gender: 'male' | 'female';
    // ....
}

type MessageType = keyof MessageDataMap;

type Message = {
  [K in MessageType]: {
    type: K;
    data: MessageDataMap[K];
  };
}[MessageType];

我会使用Type别名而不是Message的接口,因为您自然在谈论一个有区别的联合 ,而接口不能代表联合。 我会这样定义:

type Message = {
  [K in MessageType]: { type: K; data: MessageData<K> }
}[MessageType];

第一部分是映射类型 ,它产生一个对象,例如{name: {type: "name", data: string}, age: {type: "age", data: number} ,最后一部分是一个查找类型 ,获取该类型的值的并集...即{type: "name", data: string} | {type: "age", data: number} {type: "name", data: string} | {type: "age", data: number} 然后,这应该可以按您期望的那样工作:

const desiredMessage: Message = {
  type: "name",
  data: "Michael"
};

const alsoDesiredMessage: Message = {
  type: "age",
  data: 14
};

const badMessage: Message = {
  type: "name",
  data: 14
}; // error! number is not string

链接到代码

请注意,您的MessageTypeMessageData类型在某种程度上间接表示您的约束...如果MessageType开始增长, MessageData的条件类型可能无法很好地扩展。 相反,我建议使用这样的帮助程序界面:

interface MessageDataMap {
    name: string;
    age: number;
}

然后,你的MessageTypeMessageData可以表示为keyof /查找类型

type MessageType = keyof MessageDataMap
type MessageData<T extends MessageType> = MessageDataMap[T]

这与以前完全一样,但是您可以相对轻松地向MessageDataMap添加属性。

链接到代码

好的,希望能有所帮助; 祝好运!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM