TypeScript 中的超类型约束

Mic*_*ler 7 typescript

我正在尝试使用updeep图书馆。一个典型的使用例子updeep是这样的:

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

var result = u({ name: { first: 'Susan' } }, person);
Run Code Online (Sandbox Code Playgroud)

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

function u<T>(changes: {}, obj: T): T { ... }
Run Code Online (Sandbox Code Playgroud)

这捕获了第二个参数的类型也是函数的返回类型的事实。但是,它不表达的是,changes应该是一个超类型T

我想要的是对第一个参数进行一些类型检查。关键是参数中存在的值changes都应该出现在T类型参数中,并与它们对应的类型匹配。表达这个允许我们检查changes参数以确保它对类型有意义T即,是 的超类型T)。

我不确定这在 TypeScript 中是否可行。在 Java 等语言中,您有super关键字,它可用于描述对类型参数的约束。

虽然 TypeScript 不允许,但这样的事情表达了我想要的:

function u<T extends U,U extends {}>(changes: U, obj: T): T { ... }
Run Code Online (Sandbox Code Playgroud)

有人对如何表达这一点有建议吗?有一个类型安全系统来执行这样的转换会很棒。

谢谢。

Cra*_*ter 6

自 TypeScript 2.1 以来,这已经成为可能Partial<T>

原来的问题可以用以下方法解决

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


Dal*_*onF 1

对于这样的问题有一个未解决的问题,此处称为“部分类型”: 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;
  };
}
Run Code Online (Sandbox Code Playgroud)

就我个人而言,我什至更愿意避免后一部分,而尽可能多地使用可选属性。强制属性并不能真正保护您免受任何伤害;尽管它们看起来像这样,但它们并不是不可空的。

  • 虽然这些确实是不可空的,但您仍然在这里放弃了一定程度的类型安全性。例如,当我在 React 中创建组件时,我指定了“props”类型。因此,每当我在 TSX 中实例化该类型时,任何不可选的内容都是必需的。此要求由编译器强制执行。将所有内容设为可选确实为各种“半生不熟”的实例打开了大门,这些实例可能会造成很多混乱。确实,它们可以是“null”,但我必须**明确地**将它们设置为“null”。 (2认同)