代码

interface Order {
    customer: Customer,
    address: Address
}

interface Customer {
    name: string
}

interface Address {
    firstLine: string
}

interface OrderUpdateRequest {
    key: 'customer'|'address',
    value: Customer | Address
}

const myThing = {customer: {name: 'Bob'}, address: {firstLine: 'my street'}} as Order

const updateRequest = {key:'customer',  value: {name : 'Dave'}} as OrderUpdateRequest
myThing[updateRequest['key']] = updateRequest['value']

背景

Playground

以上面的操场为例,我希望能够创建一个通用接口,它将接受customeraddress作为键,然后如果键是customer,则TS知道该值将是Customer的实例.

当前问题

我无法更改订单上customer的值,因为TypeScrip要求请求的value与客户和地址一致

Type 'Customer | Address' is not assignable to type 'Customer & Address'.
  Type 'Customer' is not assignable to type 'Customer & Address'.
    Property 'firstLine' is missing in type 'Customer' but required in type 'Address'.(2322)
input.tsx(11, 5): 'firstLine' is declared here.

请注意,尽管第Infer the type value of a property based on the type value of another property in an array of object in TypeScript期的标题措辞相似,但情况和结果却大相径庭.

最新情况: Playground 2Solution Playground

推荐答案

updateRequestOrderUpdateRequest类型,因此从那里开始,TypeSCirpt将始终认为updateRequestkey属性值将是"customer" | "address"

如果希望能够将updateRequest.key指定为"customer",则需要在OrderUpdateRequest上添加泛型类型

interface OrderUpdateRequest<T extends "customer" | "address"> {
    key: T,
    value: T extends "customer" ?  Customer : Address
}

const myThing = {customer: {name: 'Bob'}, address: {firstLine: 'my street'}} as Order

const updateRequest = {key:'customer',  value: {name : 'Dave'}} as OrderUpdateRequest<"customer">
myThing[updateRequest.key] = updateRequest['value']

这个示例非常简单,如果您想添加其他可能的键,则可以对其进行改进,但它只是为了说明我的观点:

一旦输入了一个值,无论类型是如何构造的,TypeScrip将只用它的类型来标识该值.因此,为了能够根据属性的值具有不同的行为,您应该使用泛型类型

如果要使用两个以上的键,可以使用映射接口将每个键与特定类型相关联,然后在泛型类型中使用接口的键

interface OrderUpdateRequestMapping {
    customer: Customer,
    address: Address
}

interface OrderUpdateRequest<K extends keyof OrderUpdateRequestMapping> {
    key: K,
    value: OrderUpdateRequestMapping[K]
}

Typescript相关问答推荐

如何使用TypScript和react-hook-form在Next.js 14中创建通用表单组件?

Angular 17 -如何使用新的@if语法在对象中使用Deliverc值

typescript抱怨值可以是未定义的,尽管类型没有定义

防止获取发出不需要的请求

如何使用泛型类型访问对象

部分类型化非 struct 化对象参数

类型脚本中没有接口的中间静态类

缩小并集子键后重新构造类型

从子类构造函数推断父类泛型类型

为什么我的查询钩子返回的结果与浏览器的网络选项卡中看到的结果不同?

是否可以强制静态方法将同一类型的对象返回其自己的类?

打字脚本中的模块化或命名空间

声明遵循映射类型的接口

打字错误TS2305:模块常量没有导出的成员

从以下内容之一提取属性类型

编剧- Select 下拉框

递归生成常量树形 struct 的键控类型

递归JSON类型脚本不接受 node 值中的变量

剧作家测试未加载本地网址

TS 条件类型无法识别条件参数