【发布时间】:2019-11-23 01:21:58
【问题描述】:
我正在尝试实现一个通用的 inMemoryGateway 构建器。我在创建实现时遇到了打字问题:我希望能够提供没有“id”的实体(使用 typescript Omit),而不是添加缺少的“id”。但是这些类型似乎不兼容。我现在使用as any,但有人会看到更清洁的解决方案吗?
interface EntityGateway<E extends {id: string}> {
create: (entity: Omit<E, 'id'>) => E
getAll: () => E[]
}
const buildInMemoryGateway = <Entity extends {id: string}>(): EntityGateway<Entity> => {
const entities: Entity[] = [];
return {
create: (entityWithoutId: Omit<Entity, 'id'>) => {
const entity: Entity = { ...entityWithoutId, id: 'someUuid' }
// Error here on entity :
// Type 'Pick<Entity, Exclude<keyof Entity, "id">> & { id: string; }' is not assignable to type 'Entity'.
// ugly fix: const entity: Entity = { ...entityWithoutId as any, id: 'someUuid' }
entities.push(entity);
return entity
},
getAll: () => {
return entities;
}
}
}
interface Person {
id: string,
firstName: string,
age: number,
}
const personGateway = buildInMemoryGateway<Person>();
personGateway.create({ age: 35, firstName: 'Paul' }); // OK as expected
personGateway.create({ age: 23, whatever: 'Charlie' }); // error as expected
console.log("Result : ", personGateway.getAll())
【问题讨论】:
-
您对
interface OnlyAlice { id: "Alice" }; const g = buildInMemoryGateway<OnlyAlice>(); g.create({}); g.getAll()[0].id有什么期望? -
我希望得到'someUuid',但这是我不会有的用法......
-
但是该值的类型在类型系统中是
"Alice"。你所做的并不安全,因为Omit<E, "id"> & {id: string}不一定与E相同,即使E extends {id: string}也是如此。这就是编译器警告您的原因。如果您不希望id永远是字符串文字类型,那么在您正在做的时候使用类型断言并继续前进。否则,有一些方法可以使其类型安全,但这很丑陋,因为您必须将Omit<E, "id"> & {id: string}之类的类型拖到以前使用E的地方。 -
问题与this question中的问题基本相同。
标签: typescript typescript-typings