简体   繁体   English

typescript 扩展类型与接口

[英]typescript extending types vs interfaces

This might a be relatively noob question, I have an interface这可能是一个比较菜鸟的问题,我有一个界面

interface Employee {
   name: string
}

and I would like to have an extended version of this after it being saved into the DB:在将其保存到数据库中后,我想要一个扩展版本:

interface EmployeeDb {
   id: string,
   name: string
}

I would like to differentiate it when handling checks so after saving data in my storage, the type checker won't complain about not having id value.我想在处理检查时区分它,以便在我的存储中保存数据后,类型检查器不会抱怨没有 id 值。 Meaning I want to avoid using this:意思是我想避免使用这个:

interface Employee {
   id?: string,
   name: string
}

so I don't have to check for id everywhere.所以我不必到处检查身份证。

So I am trying to do it this way:所以我想这样做:

type Employee = {
   name: string
}

type IDatabaseObject<T> = {
  id: IDatabaseObjectId;
  [P in keyof T]: T[P];
};

type EmployeeDb = IDatabaseObject<Employee>

which the IDE gives an error with the top syntax其中 IDE 给出了顶级语法的错误

A computed property name must be of type 'string', 'number', 'symbol', or 'any'.ts(2464)计算属性名称必须是“string”、“number”、“symbol”或“any”类型。ts(2464)

so I tried to use interface and extend it所以我尝试使用接口并扩展它

interface IDatabaseObject { 
   id: string
}

interface EmployeeDb extends Employee, IDatabaseObject {}

but in the backend code when I try to use this setup I get an error from vscode eslint again.但是在后端代码中,当我尝试使用此设置时,我再次从 vscode eslint 收到错误。 I have a small code here that adds the data to localstorage, generates a id and returns the data.我这里有一个小代码,将数据添加到 localstorage,生成一个 id 并返回数据。 see code:见代码:

class DbAsyncStorageTemplate<
    InputDataType,
    OutputDataType extends IDatabaseObject
> {

    async addEntry(object: InputDataType): Promise<OutputDataType> {

        const id: string = generateUuid()
        const dbObject = { id, ...object }
        dbObject.id = id

        // add the item to AsyncStorage directly
        await AsyncStorage.setItem(id, JSON.stringify(object))

        // ERROR HERE: return the new object
        return dbObject as OutputDataType
    } 
    }
}

but I get an error from the IDE (eslint) for the last line但我从最后一行的 IDE (eslint) 中收到错误

Conversion of type '{ id: string;类型转换 '{ id: string; } & InputDataType' to type 'OutputDataType' may be a mistake because neither type sufficiently overlaps with the other. } & InputDataType' 键入 'OutputDataType' 可能是错误的,因为两种类型都没有充分重叠。 If this was intentional, convert the expression to 'unknown' first.如果这是故意的,请先将表达式转换为“未知”。 '{ id: string; '{ id: 字符串; } & InputDataType' is assignable to the constraint of type 'OutputDataType', but 'OutputDataType' could be instantiated with a different subtype of constraint 'any'. & InputDataType' 可分配给 'OutputDataType' 类型的约束,但 'OutputDataType' 可以用约束 'any' 的不同子类型实例化。

any recommendation on how to do this properly?关于如何正确执行此操作的任何建议?

I think you are looking for this: https://www.typescriptlang.org/docs/handbook/advanced-types.html#:~:text=an%20intersection%20type%3A-,//%20Use%20this%3A,%7D,-Try我想你正在寻找这个: https://www.typescriptlang.org/docs/handbook/advanced-types.html#:~:text=an%20intersection%20type%3A-,//%20Use%20this%3A ,%7D,-尝试

You are trying to create a new type (IDatabaseObject) based on an old type (Employee, for instance; or T, in the generic case).您正在尝试基于旧类型(例如 Employee;或一般情况下的 T)创建新类型 (IDatabaseObject)。 This is a Mapped Type.这是一个映射类型。

In your code,在你的代码中,

[P in keyof T]: T[P]

returns your old type rather than members of that old type.返回您的旧类型而不是该旧类型的成员。 So you need to close the curly brackets and intersect it with any other new members you want to add.因此,您需要关闭大括号并将其与您要添加的任何其他新成员相交。

ie do the following for IDatabseObject即为 IDatabseObject 执行以下操作

type IDatabaseObject<T> = {
    id: number;
} & {
    [P in keyof T]: T[P];
};

I believe you're looking for intersections of types .我相信您正在寻找类型的交集

type Employee = {
   name: string
}

type EmployeeDb = {
  id: string;
} & Employee;

You could also define the raw DB interface and use Pick or Omit utilities as needed.您还可以定义原始数据库接口并根据需要使用PickOmit实用程序。

Pick Utility 选择实用程序

interface Todo {
  title: string;
  description: string;
  completed: boolean;
}

type TodoPreview = Pick<Todo, "title" | "completed">;

const todo: TodoPreview = {
  title: "Clean room",
  completed: false,
};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM