我有一个扩展2个其他接口的接口。
除了以下几点外,新接口是相同的:字段'_id'应该是字符串而不是ObjectId(以便于服务器端操作)。
是否可以覆盖新界面中的字段类型?当我这样做时,tslint会告知新界面未正确扩展先前的界面。
我还想避免使用诸如_id : ObjectId | string
export interface AchievementDb {
_id: ObjectID;
title: string;
description: string;
// more stuff
}
export interface AchievementUserProgress {
_id: ObjectID;
progress: number;
status: UserAchievementStatus;
// more stuff
}
export interface AchievementFull extends AchievementDb, AchievementUserProgress {
_id: string;
}
答案 0 :(得分:4)
我会看到两个选择:
interface WithID {
_id: ObjectID;
}
interface AchievementDbBase {
title: string;
description: string;
// more stuff
}
interface AchievementDb extends AchievementDbBase, WithID {
}
interface AchievementUserProgressBase {
progress: number;
// more stuff
}
interface AchievementUserProgress extends AchievementUserProgressBase, WithID {
}
interface AchievementFull extends AchievementDbBase, AchievementUserProgressBase {
_id: string;
}
看看排除类型(https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html)允许对类型进行这种类型的映射: http://ideasintosoftware.com/typescript-advanced-tricks/
在您的情况下:
interface AchievementFull extends Omit<AchievementDb, '_id'>, Omit<AchievementUserProgress, '_id'> {
_id: string;
}
答案 1 :(得分:3)
有几种选择。
我们可以在接口上使用通用类型参数来指定id
的类型。我们可以指定一个默认的类型参数,以便在必要时可以继续使用不带类型参数的接口:
export interface AchievementDb<T = ObjectID> {
_id: T;
title: string;
description: string;
// more stuff
}
export interface AchievementUserProgress<T = ObjectID> {
_id: T;
progress: number;
status: UserAchievementStatus;
// more stuff
}
export interface AchievementFull extends AchievementDb<string>, AchievementUserProgress<string> {
}
另一种选择是使用Pick
和Exclude
从接口中删除该字段,以便我们可以按需覆盖它(您会发现其他人定义为Omit
的相似类型)
type ExcludeId<T> = Pick<T, Exclude<keyof T, '_id'>>
export interface AchievementFull extends ExcludeId<AchievementDb>, ExcludeId<AchievementUserProgress> {
_id: string;
}
答案 2 :(得分:1)
您试图覆盖AchievementFull
接口中的字段类型的事实表明代码有味道,并且无法扩展其他接口。您不能在子界面中将_id
的类型从ObjectID
更改为string
。
也许您应该考虑以不同的方式组织您的界面。
TypeScript不允许您覆盖子接口中的父接口属性。
答案 3 :(得分:0)
基于其他一些答案,我认为这更干净(基于我的真实代码的类型):
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
interface HTMLEvent<T> extends Omit<Event, 'target'> {
target: T;
}
我将这种类型用于Angular事件,因此不需要像docs中那样强制转换目标类型:
onKey(event: KeyboardEvent) { // with type info
this.values += (<HTMLInputElement>event.target).value + ' | ';
}
并使用它:
onInput(event: HTMLEvent<HTMLInputElement>) {
this.value = event.target.value;
}