很难 Select 一个适当的总结,所以让我来解释一下我的问题.我有一堆类,每个类都有一个toJSON方法,可以将类转换为它的JSON表示.我想 for each 方法添加一个新的可选参数,它允许我只返回类属性的一个子集,而不是所有属性.该方法的返回类型应该根据开发人员 Select 的属性进行相应的更改.

我想使此类型安全,但我还没有达到完全满足我的需要的程度.以下是缺少的简短示例:

interface IUser {
  id: string;
  name: string;
  age: number;
}

const fullUser = user.toJson(); // full "IUser"
const truncatedUser = user.toJson({ attributes: ['name'] }); // Pick<IUser, 'name'>

fullUser.id // works
truncatedUser.id // should throw an error, but tsc compiles

完整的例子,我已经实现了到目前为止.

// Using the generic here, because I want to pass interface IUser, or IABC, or IDEF etc
interface IJSONExportOptions<Type> {
  /** A list of object properties that are included in the the resulting JSON.  */
  attributes?: (keyof Type)[];
}

interface IUser {
  id: string;
  name: string;
  age: number;
}

class User {
  private id: string;
  private name: string;
  private age: number;

  constructor() {
    this.id = '1';
    this.name = 'Jon Doe';
    this.age = 20;
  }

  toJSON(opts?: IJSONExportOptions<IUser>) {
    const fullObj: IUser = {
      id: this.id,
      name: this.name,
      age: this.age,
    };

    if (!opts?.attributes?.length) {
      return fullObj as Pick<IUser, keyof IUser>;
    }

    const truncatedUser: Partial<Pick<IUser, keyof IUser>> = {};
    for (const key of opts?.attributes) {
      const val = fullObj[key];
      truncatedUser[key] = val;
    }
    return truncatedUser as Pick<IUser, keyof IUser>;
  }
}

const user = new User()
const fullUser = user.toJSON();

console.log(fullUser.age);

const truncatedUser = user.toJSON({ attributes: ['name'] });

console.log(truncatedUser.age); // I want that tsc throws an error here, but also that my IDE does not provide autocomplete for "undefined" properties

如果这很重要,代码使用typescript 4.4.3(升级是一个选项).

如有任何帮助,我们不胜感激.

推荐答案

首先想到的是重写接口以获取键而不是作为一个整体的类型:

interface IJSONExportOptions<Keys extends string> {
  /** A list of object properties that are included in the the resulting JSON.  */
  attributes?: Keys[];
}

然后,我们可以使用缺省为keyof IUser的通用参数:

  toJSON<Keys extends keyof IUser = keyof IUser>(
    opts?: IJSONExportOptions<Keys>,
  ): Pick<IUser, Keys> {

因此,如果没有attributes,则TypeScrip将默认为keyof IUser,因为它无法推断出Keys.docs

最后,我们可以使用断言:

return truncatedUser as Pick<IUser, Keys>;

Playground

Typescript相关问答推荐

Angular -使用Phone Directive将值粘贴到控件以格式化值时验证器不工作

处理API响应中的日期对象

如何在方法中定义TypeScript返回类型,以根据参数化类型推断变量的存在?

如何使用Zod使一个基于其他字段值的字段为必填字段?

使用数组作为类型中允许的键的列表

在打印脚本中使用泛型扩展抽象类

如何编写在返回函数上分配了属性的类型安全泛型闭包

如何在脚本中输入具有不同数量的泛型类型变量的函数?

为什么&Quot;元素隐式具有';Any';类型,因为...即使我已经打字了,也不能作为索引显示错误吗?

如何定义这样一个TypeScript泛型,遍历路由配置树并累积路径

在抽象类构造函数中获取子类型

如何将通用接口的键正确设置为接口的键

如何调整项目数组,但允许权重影响顺序

基于区分的联合键的回调参数缩小

React Context TypeScript错误:属性';firstName';在类型';iCards|iSearch';

在对象数组中设置值

带有过滤键的 Typescript 映射类型

Mongodb TypeError:类继承 events_1.EventEmitter 不是对象或 null

为什么在 useState 中设置 React 组件是一种不好的做法?

通过函数将对象文字类型映射到另一种类型的方法或解决方法