首页 > 解决方案 > 是否有一种类型安全的方式来表示函数在传递 T 时返回 T 类型的对象,但返回 Partial 类型的对象什么时候通过的?

问题描述

我正在编写函数来清理传递给我的 CRUD 操作的输入;例如,我不希望该操作可以创建或更新用户以设置指示不受限制的管理员的内部标志。

为此,我只使用 lodash_.pick将已知属性从输入中投影出来:

interface IUser {
    username: string;
    password: password;
}

interface IUserInternal {
    superuser: boolean;
}

function cleanUser(user: IUser): IUser {
    return _.pick(user, 'username', 'password');
}

function createUser(user: IUser) {
    db.create(cleanUser(user));
}

function updateUser(id: string, user: Partial<IUser>) {
    const old = db.get(id);
    db.update(id, {...old, ...cleanUser(user)});
}

我不能在这里依赖类型检查,因为这是服务边界,我想在添加全面验证之前先坚持一些快速而肮脏的东西。

上面的问题是在最后一点:我显然不能打电话cleanUser()Partial<IUser>我也不能cleanUser()take 和 return a Partial<IUser>,因为那样我就失去了确保我选择了所有属性的类型检查器。实现本身将起作用,因为 pick 只会跳过在源对象中找不到的属性。

我尝试制作签名cleanUser<T extends Partial<IUser>>(user: T): T以表示我正在返回传入的相同内容,但只是告诉我返回值不可分配给T. 我尝试添加一个重载签名cleanUser<Partial<IUser>>(user: Partial<IUser>),但即使传入普通用户,TS 也会选择它。

有没有一种干净的方式来表达这一点,或者我只是去“我知道我在做什么”并抑制类型错误?

标签: typescript

解决方案


您可以为此使用函数重载:

function cleanUser(user: IUser): IUser;
function cleanUser(user: Partial<IUser>): Partial<IUser>;
function cleanUser(user): any {
  return _.pick(user, 'username', 'password');
}

推荐阅读