打字稿泛型类型检查失败

时间:2019-08-22 22:25:35

标签: typescript generics

// 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中的某些配置?知道如何解决吗?

2 个答案:

答案 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()

这可行,但增加的复杂性可能不值得稍微减少冗余。哦,很好。

希望有帮助。祝你好运!

Link to code