// RepositoryBase.ts
export type FieldsMapping<T> = { readonly [k in keyof Required<T>]: string };
export abstract class RepositoryBase<T> {
protected abstract readonly COLUMNS: FieldsMapping<T>;
}
// UsersRepository.ts
import { FieldsMapping, RepositoryBase } from './RepositoryBase';
interface User {
firstName: string;
lastName: string;
email?: string;
}
export class UsersRepository extends RepositoryBase<User> {
protected readonly COLUMNS = {
firstName: 'first_name',
lastName: 'last_name',
email: 'email',
extra: 'non_existing_column',
};
}
在COLUMNS
中声明UsersRepository
不会产生任何编译错误,即使extra
接口上不存在User
键。
如果我将类型添加到COLUMNS
中的UserRepository
中,例如:COLUMNS: FieldsMapping<User>
,则会引发错误。
我不想在继承RepositoryBase
的每个类上重新声明类型。您知道为什么会这样吗?可能是由于abstract
造成的吗?还是由于tsconfig.json
中的某些配置?知道如何解决吗?
答案 0 :(得分:1)
const userLike = {
firstName: '',
lastName: '',
email: '',
az: ''
};
const user: User = userLike;
Typescript允许这种“灵活”的分配。他对声明更加严格。
关于此问题,有一个有趣的建议:https://github.com/microsoft/TypeScript/issues/12936
答案 1 :(得分:1)
使用extends
扩展接口或类时,可以通过添加新属性或缩小现有属性来使子接口/子类更窄。因此,在TypeScript中完全可以接受COLUMNS
的{{1}}属性比UserRepository
的{{1}}属性更加具体。这就是COLUMNS
的明确目的。
如果您选择注释 RepositoryBase<User>
属性extends
的类型为COLUMNS
(相当于您的UserRepository
)并使用新的对象字面量,您将获得excess property checking,并将标记额外属性。
如果这对您有用,那么您就应该这样做……有点多余(您必须在Record<keyof User, string>
的通用参数和{{的注释中都写FieldsMapping<User>
1}}属性),但还算干净。
否则,我对此没有任何很好的修复,主要是因为User
属性很难以编程方式进行操作。 (例如RepositoryBase<User>
不包含COLUMNS
,因此protected
无效)。
我想我能得到的最接近的是名为keyof UserRepository
之类的通用方法,它将只接受没有已知额外属性的字段映射...该方法将仅返回其输入,因此您将使用它来初始化COLUMNS
属性:
UserRepository["COLUMNS"]
赞:
strictColumns()
这可行,但增加的复杂性可能不值得稍微减少冗余。哦,很好。
希望有帮助。祝你好运!