首页 > 解决方案 > 如何避免`后续的属性声明必须具有与接口相同的类型`

问题描述

我有一些接口,它有一个枚举字段。还希望对此接口进行重载,这将在某些特定枚举值的情况下采用更多属性。

举个例子:

enum CellValueType {
    DATE,
    STRING,
    NUMBER
}


export interface TableCell {
    type: CellValueType;
    value: string; // ...
}

export interface TableCell {
    type: CellValueType.DATE;
    format: string; // Should be exist only on the DATE type
    value: string; // ...
}

但是,问题是使用界面时出现错误:

后续的属性声明必须具有相同的类型。属性“type”必须是“CellValueType”类型,但这里有“CellValueType.DATE”类型。

错误是可以理解的,没有问题。

主要问题是如何以合法的方式避免它。

我知道,我可以使用type而不是interface得到这个结构:

export type TableCell = {
    type: CellValueType;
    value: string;
} | {
    type: CellValueType.DATE;
    format: string; 
    value: string;
}

工作得很好,但问题是类不能实现联合类型。


无法按预期工作,DATE但仍与第一个签名兼容。要正常工作,需要将type: CellValueType其更改为type: Exclude<CellValueType, CellValueType.DATE>

此外,我可以仅为枚举类型创建一个子接口,DATE但也希望避免为每种情况创建一个接口。

标签: typescriptoverloading

解决方案


当您以相同的名称定义两个接口时,将执行声明合并

export interface TableCell {
    type: CellValueType;
    value: string; // ...
}

export interface TableCell {
    type: CellValueType.DATE;
    format: string; // Should be exist only on the DATE type
    value: string; // ...
}

这是您在尝试CellValueTypeCellValueType.DATE. 引用手册

如果接口都声明了同名但类型不同的非函数成员,编译器将发出错误

现在,当您尝试使用联合来创建所需的类型时,您遇到了另一种设计行为 - 由于CellValueType.DATE是 的成员CellValueType,因此选择了更广泛的类型(想想看:A | ... | A | B与 相同A | B):

type isInType = CellValueType.DATE extends CellValueType ? true : false; //true;
type isNotInType = CellValueType extends CellValueType.DATE ? true : false; //false;
type cellType = TableCell["type"]; //CellValueType

既然如此,为什么不想创建扩展基本类型的接口呢?这是一个完全有效的抽象策略。看看下面的例子(注意as const断言,否则类型CellValueType.DATE将扩大到CellValueType):

export enum CellValueType {
    DATE,
    STRING,
    NUMBER
}

interface TableCell {
    value: string;
}

export interface DateCell extends TableCell {
    type: CellValueType.DATE;
    format: string;
}

export interface NumberCell extends TableCell {
    //number-specific props here
}

export class DateCell implements DateCell {
    format = "yyyy-MM-dd";
    type = CellValueType.DATE as const;
    value = "2021-02-22";
}

操场


推荐阅读