在 TypeScript 中覆盖接口的属性

问题描述 投票:0回答:6

我知道在扩展接口中重写接口的属性、修改其类型是被禁止的。

我正在寻找一种替代解决方案,它允许我不复制第一个界面的内容(它相当大)。

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

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

该接口是在库中定义的。 我无法修改它(例如添加泛型)来满足我在扩展接口中的需求。

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

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'.

我还尝试将两个界面合并在一起:

type Extended = OriginalInterface & NewInterfaceWithOverridingPropertiesOnly;

虽然编译通过了,但是不起作用。如果您声明此类型的变量,则只能分配具有与

OriginalInterface
兼容结构的对象。

我觉得 TypeScript 的类型系统没有为我提供任何其他方式来表达我需要声明一个从 OrginalInterface 派生的新类型

。我不需要将新类型分配给 
OriginalInterface
 ;我只需要它来重用 
OriginalInterface
 的大部分属性。

我需要类似映射类型的东西,以及属性受到影响的条件。也许来自预发布 TypeScript 2.8 的

条件类型?还是应该复制第一个界面的内容?

typescript types overriding
6个回答
24
投票
更新,2018-08

TypeScript 2.8 引入了

Exclude<T, U>

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

此外,在 TypeScript 2.9 中,

keyof any

string
 扩展到 
string | number | symbol
,因此下面的 
Diff<T, U>
 会导致错误,可以通过将 
Diff<T extends string, U extends string>
 更改为 
Diff<T extends keyof any, U extends keyof any>
 来修复。  此更改已在下面进行。


原始答案,2018-03

是的,

条件类型将启用此功能,尽管您也可以在没有它们的情况下获得此行为

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

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>

 的定义,以尊重 
T
 中属性的可选/必需状态,其键不存在于 
U
 中。

我认为这有你想要的行为。 希望有帮助;祝你好运!


12
投票
使用 TypeScript

省略:

省略

通过从 T 中选取所有属性然后删除 K 来构造类型

// original interface interface A { a: number; b: number; // we want string type instead of number } // Remove 'b' type BTemp = Omit<A, 'b'>; // extends A (BTemp) and redefine b interface B extends BTemp { b: string; } const a: B = { a: 5, b: 'B' }

enter image description here


3
投票
自 2.9 以来的重大更改:

https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#keyof-now-includes-string-number-and-symbol-keys

使用

Extract<keyof T, string>

避免

类型“keyof T”不满足约束“string”。

编辑:会为此写评论,但缺乏必要的声誉


3
投票
简短回答:

type Overrided = Omit<YourInterface, 'overrideField'> & { overrideField: <type> };
    

1
投票
我一直用这个来约会。我有一个通用库,可在后端和前端 React 应用程序中使用,用于特定于域的实体的类型定义。

通过数据库接收数据时,日期字段是

Date

 对象,但当由 REST API 使用时,日期作为字符串对象(ISO 日期)。由于为两者提供单独的接口定义是不现实的(这会违背拥有公共库的目的),因此我在公共库中定义类型如下:

type IsoDateString = string type DatesAsIsoString<T, U extends keyof T> = Omit<T, U> & { [key in U]: IsoDateString } // Example object interface User { id: number registeredAt: Date } // on the back end const user: User = await getUserFromDatabase() console.log(user.registeredAt) // Date user.registeredAt.getTime() // ms epoch // on the front end, define type FetchedUser = DatesAsIsoString<User, 'registeredAt'> // then use const user: FetchedUser = await getUserFromApi() console.log(user.registeredAt) // string, e.g. 2020-08-25T05:52:03.000Z const actualDate = new Date(user.registeredAt) // date object
    

0
投票
对于多次覆盖,请使用

Omit<YourInterface, 'propertyA' | 'propertyB'>

:

export interface ErrorResponseSanitizedInterface extends Omit< ErrorResponseInterface, 'error' | 'data' > { error: string | SanitizedMessage.DEFAULT | ErrorDataInterface['error'] data: SanitizedMessage.DEFAULT | ErrorDataInterface['data'] stack: ErrorResponseFullInterface['stack'] }
    
© www.soinside.com 2019 - 2024. All rights reserved.