繁体   English   中英

Typescript 创建一个类型,其属性是接口的属性

[英]Typescript Create a type whose properties are the properties of an interface

我有一个接口定义如下

export interface RoutingMap {
    ticket: {
        id: number
    },
    car: {
        model: string,
        make: number
    }
}

我希望能够为 object 创建一个接口,该接口具有 2 个属性 - 1 是RoutingMap RoutingMapKey的类型。

在伪代码中,我想象它看起来像这样

export interface RoutingMessage {
    resource: keyof RoutingMap,
    params: RoutingMap["resource"]
}

最终目标是让我能够构造这样的对象

const msg: RoutingMessage = {
    resource: "ticket",
    params: { id: 10 }
}

const invalidMsg: RoutingMessage = {
    resource: "something", //TS error - "something" is not a key of routing map
    params: { id: 10 }
}

const invalidMsg2: RoutingMessage = {
    resource: "car"
    params: { model: "tesla", make: true } //TS error - "make" is not a boolean
}

const invalidMsg3: RoutingMessage = {
    resource: "car"
    params: { id: 123 } //TS error - id is not assinable to  {model: string, make: boolean}
}

RoutingMap会随着时间的推移而扩展,人们应该能够根据键(及其值)创建特定的对象

正如您从伪代码示例中看到的那样,我可以为资源设置约束,但我需要一种方法来约束 params 属性以仅允许与RoutingMap中的Key签名匹配的对象

export interface RoutingMessage {
    resource: keyof RoutingMap,
    params: RoutingMap[this["resource"]]
}

因为有有限数量的键匹配keyof RoutingMap ,您可以将RoutingMessage编写为 object 类型的联合,其中联合的每个元素对应于特定的键,如下所示:

type RoutingMessage = {
    resource: "ticket";
    params: {
        id: number;
    };
} | {
    resource: "car";
    params: {
        model: string;
        make: number;
    };
}

您可以通过将RoutingMessage编写为“分布式 object 类型”(从microsoft/TypeScript#47109借用的术语)以编程方式从RoutingMap计算 RoutingMessage,其中我们制作了一个映射类型,其中RoutingMap中具有键K的每个属性都映射到所需的 object 类型key,然后我们立即使用keyof RoutingMap对其进行索引,生成所需的联合。

type RoutingMessage = { [K in keyof RoutingMap]:
  { resource: K, params: RoutingMap[K] }
}[keyof RoutingMap];

使用上面的定义,每当向RoutingMap添加新属性时, RoutingMessage都会根据需要获得新的联合成员。


让我们确保它的行为符合您的要求:

const msg: RoutingMessage = {
  resource: "ticket",
  params: { id: 10 }
}; // okay

const invalidMsg: RoutingMessage = {
  resource: "something", // error!
  //~~~~~~ <-- Type '"something"' is not assignable to type '"ticket" | "car"'
  params: { id: 10 }
};

const invalidMsg2: RoutingMessage = {
  resource: "car",
  params: { model: "tesla", make: true } // error!
  //  --------------------> ~~~~
  // Type 'boolean' is not assignable to type 'number'.
};

const invalidMsg3: RoutingMessage = {
  resource: "car",
  params: { id: 123 } // error!
  // -----> ~~~~~~~
  // Type '{ id: number; }' is not assignable to type '{ model: string; make: number; }' 
};

看起来不错!

Playground 代码链接

暂无
暂无

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

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