TypeScript中的超类型约束

9

我正在尝试使用updeep库。使用updeep的典型示例如下:

var person = {
  name: {
    first: 'Jane',
    last: 'West'
  }
};

var result = u({ name: { first: 'Susan' } }, person);

这里的想法是result将是person的克隆,但name.first的值已更改。 你可以想象这个函数u在TypeScript中定义为:

function u<T>(changes: {}, obj: T): T { ... }

这表明第二个参数的类型也是函数的返回类型。但它没有表达出“changes”应该是“T”的超级类型的事实。
我希望第一个参数能进行一些类型检查。关键在于,出现在“changes”参数中的值都应该出现在“T”类型参数中,并且与其对应的类型相匹配。表达这一点可以让我们检查“changes”参数,以确保它针对类型“T”是合理的(即,是“T”的超级类型)。
我不确定TypeScript是否支持此功能。在Java等语言中,有“super”关键字可用于描述类型参数的约束。
虽然TypeScript不允许使用,但是类似于以下内容可以表达我的意思:
function u<T extends U,U extends {}>(changes: U, obj: T): T { ... }

有没有关于如何表达这个问题的建议?希望能够有一个类型安全的系统来执行这样的转换。

谢谢。


1
你找到解决办法了吗?确实,就像你在另一条评论中所说的,使用Partial来实现这一点会使每个属性变为可选,因此会牺牲类型安全性。 - Laurens
@Laurens 这不应该影响类型安全性。事实上,这正是所期望的:一个对象类型与 T 相同,除了每个键都是可选的,它是 T 的超类型:任何 T(具有所有键)都可以分配给部分类型(其中键是可选的)。它并不是 每个 超类型,因为每个键的类型必须要么与 T 中的类型相同,要么根本不存在。 - Peeja
2个回答

6
自 TypeScript 2.1 版本起,使用 Partial<T> 可以实现这一点。
使用以下代码解决原始问题: function u<T>(changes: Partial<T>, obj: T): T { ... }

1

这方面有一个未解决的问题,称为“Partial types”,可以在此处找到:https://github.com/Microsoft/TypeScript/issues/4889

Facebook的Flow也有类似的(但是故意不记录)$Shape<>类型,在React的setState()中可以看到其类型。

所以基本上,没有自动执行此操作的功能。但是,您可以通过手动执行以下操作来解决:

interface IPartialPerson {
  name?: {
    first?: string;
    last?: string;
  };  
  someOptionalProperty?: string;
}

interface IPerson extends IPartialPerson {
  name: {
    first: string;
    last: string;
  };
}

个人而言,我更喜欢尽可能使用可选属性,甚至避免使用后者。强制属性实际上并不能保护你免受任何影响;它们看起来像非空,但实际上不是。

2
虽然这些是非空的,但你在这里仍然放弃了一定程度的类型安全性。例如,在React中创建组件时,我会指定一个props类型。每当我在TSX中实例化该类型时,任何不是可选的都是必需的。编译器强制执行此要求。将所有内容都设置为可选项确实为各种可能引起混乱的“半成品”实例打开了大门。当然,它们可以是null,但我必须明确地将它们设置为null - Michael Tiller
@MichaelTiller 我确实觉得它们有时候很有用,而且在React props中,我倾向于使用非可选属性(以及在propTypes中设置一个isRequired!)。但我担心的是,它们“看起来”比它们实际提供的类型安全性更多,因此我避免让自己(以及阅读代码的任何人)假设可选属性能够防止空值。 - DallonF
1
如果您使用了 Partial<>,那么是否会允许额外的、不正确的属性?它实际上并没有约束到一个超类型,而是约束到一个超类型的子类型或类似的东西;也就是说,它太过宽松了。 - Eamon Nerbonne
�空性问题已�解决了(一段时间了😉),添加编译器选项以防止类�被��设置为 null。 - Laurens

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接