在 TypeScript 中覆盖接口的属性 [英] Override the properties of an interface in TypeScript

查看:874
本文介绍了在 TypeScript 中覆盖接口的属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道在扩展接口中重写接口的属性,修改它们的类型,是被禁止的.

I know that overriding properties of an interface in an extended interface, modifying their types, is forbidden.

我正在寻找一种替代解决方案,它可以让我不复制第一个界面的内容(它非常大).

I'm looking for an alternative solution that would allow me to not copy the contents of the first interface (it's pretty big).

下面是我的第一个天真的方法.鉴于该基本接口:

Here is below my first naive approach. Given that base interface:

interface OrginalInterface {
    title?: string;
    text?: string;
    anotherProperty?: SomeType;
    // lots of other properties
}

这个接口是在一个库中定义的.我无法修改它(例如,添加泛型)以满足我在扩展接口中的需求.

This interface is defined in a library. I can't modify it (ie. add generics, for example) just to satisfy my needs in the extended interface.

在包装库(我的)使用的扩展接口中,我想重用现有的接口,同时使一些字段具有不同的类型:

In the extended interface, used by a wrapper library (mine), I want to reuse the existing interface, while making some fields having a different type:

interface ExtendedInterface extends OriginalInterface {
    title?: string | ReactElement<any>;
    text?: string | ReactElement<any>;
}

但这是不可能的.

error TS2430: Interface 'ExtendedInterface' incorrectly extends interface 'OriginalInterface'.
  Types of property 'title' are incompatible.
    Type 'ReactElement<any>' is not assignable to type 'string'.

我也尝试将两个接口合并在一起:

I also tried to merge the two interfaces together:

type Extended = OriginalInterface & NewInterfaceWithOverridingPropertiesOnly;

虽然这通过编译,但它不起作用.如果您声明一个具有这种类型的变量,您将只能分配具有与 OriginalInterface 兼容的结构的对象.

While this passes the compilation, it does not work. If you declare a variable with this type, you'll only be able to assign objects that have a compatible structure with OriginalInterface.

我觉得 TypeScript 的类型系统没有为我提供任何其他方式来表达我需要从 OrginalInterface 声明一个新类型 衍生.我不需要将新类型分配给 OriginalInterface ;我只需要它来重用 OriginalInterface 的大部分属性.

I feel like TypeScript's type-system don't offers me any other way to express my need to declare a new type derived from OrginalInterface. I don't need the new type to be assignable to OriginalInterface ; I just need it to reuse most properties of OriginalInterface.

我需要诸如映射类型之类的东西,其中包含影响属性的条件.也许 条件类型 来自预发布的 TypeScript 2.8?还是我应该复制第一个界面的内容?

I'd need something like mapped types with a condition on which properties are affected. Maybe Conditional types from pre-release TypeScript 2.8? Or should I copy the first interface's contents?

推荐答案

UPDATE, 2018-08

TypeScript 2.8 引入 Exclude 其行为类似于下面为所有类型(不仅仅是键类型)定义的 Diff.如果您使用的是 TypeScript 2.8 或更高版本,则绝对应该使用 Exclude<> 而不是 Diff<>.

UPDATE, 2018-08

TypeScript 2.8 introduced Exclude<T, U> which behaves like the Diff<T, U> defined below for all types (not just key types). You should definitely use Exclude<> instead of Diff<> if you are using TypeScript 2.8 or above.

此外,在 TypeScript 2.9 中,keyof anystring 扩展为 string |数量 |符号,所以下面的Diff 引起的错误可以通过将Diff 更改为 来修复>Diff.此更改已在下方进行.

Also, in TypeScript 2.9, keyof any was expanded from string to string | number | symbol, so the below Diff<T, U> caused errors which can be fixed by changing Diff<T extends string, U extends string> to Diff<T extends keyof any, U extends keyof any>. This change has been made below.

是的,条件类型将启用此,尽管你也可以在没有它们的情况下获得这种行为.

这个想法是从原始界面中提取属性,然后用新的替换它们.像这样:

The idea is to pull properties out of the original interface and then replace them with new ones. Like this:

type Diff<T extends keyof any, U extends keyof any> = 
  ({ [P in T]: P } & { [P in U]: never } & { [x: string]: never })[T];
type Overwrite<T, U> = Pick<T, Diff<keyof T, keyof U>> & U;

interface OriginalInterface {
  title?: string;
  text?: string;
  anotherProperty?: SomeType;
  // lots of other properties
}
interface Extension {
  title?: string | ReactElement<any>;
  text?: string | ReactElement<any>;
}

interface ExtendedInterface extends Overwrite<OriginalInterface, Extension> {};

const ext: ExtendedInterface = {};  // okay, no required properties
ext.text; // string | ReactElement<any> | undefined
ext.title; // string | ReactElement<any> | undefined
ext.anotherProperty; // SomeType | undefined

我更改了 Overwrite 的定义,以尊重 T 的属性的可选/必需状态,其键不在 中U.

I changed the definition of Overwrite<T,U> to respect the optional/required status of properties from T whose keys are not present in U.

我认为这具有您想要的行为.希望有所帮助;祝你好运!

This has the behavior you want, I think. Hope that helps; good luck!

这篇关于在 TypeScript 中覆盖接口的属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆