我试图创建一个用对象初始化的TypeScript类,该类有一个方法,该方法只能将该对象的键作为参数.所以:

class MyClass {
  properties = {};

  constructor(properties) {
    this.properties = properties;
  }

  // Passed propNames should only be keys of this.properties
  pick(...propNames) {
    return propNames.reduce((obj, name) => ({ 
      ...obj, 
      [name]: this.properties[name]
    }), {});
  }
}

这似乎类似于this problem,但我不知道如何在这种情况下应用它,因为属性是从外部传入的.

const props = { key: 'value', key2: 'value2' };
interface PropKeys {
  key: string;
  key2: string;
}
type KeyName = keyof(PropKeys);

// But what do I do to the class to get this to work?
const instance = new MyClass(props);
instance.pick('key', 'key2'); // Great
instance.pick('key3'); // Should throw a type error

这可能吗?有没有一种方法可以不显式定义InstanceKeys,而是从初始化实例时传递的props 派生它们?

我试着用泛型来概括我的 idea ,可能是这样的:

class MyClass {
  properties = {};

  constructor<Type>(properties: Type) {
    this.properties = properties;
    type TypeKeys = keyof(Type);
  }
  
  pick(...propNames: TypeKeys[]) {
    return propNames.reduce((obj, name) => ({ 
      ...obj, 
      [name]: this.properties[name]
    }), {});
  }
}

但这会引发两种类型的错误:

  • <Type>上:"类型参数不能出现在构造函数声明上."
  • TypeKeys[]上:"找不到名称‘TypeKeys’."(我的意思是,这是有道理的;它超出了范围.)

UPDATE:这感觉更接近了,但我遇到了一个问题,即首先在类(构造函数上方)上定义属性:

class MyClass<PropType extends Properties> {
  properties: PropType = {};

  constructor(properties: PropType) {
    this.properties = properties;
  }

  pick(...propNames: Array<keyof(PropType)>) {
    return propNames.reduce((obj, name) => ({ 
      ...obj, 
      [name]: this.properties[name]
    }), {});
  }
}

我在那条线上遇到的TS错误是

Type '{}' is not assignable to type 'PropType'. '{}' is assignable to the constraint of type 'PropType', but 'PropType' could be instantiated with a different subtype of constraint 'Properties'

这里的问题是,传入的任何properties都可能有自己的键,但必须是类型属性的实例,这会限制值.

推荐答案

泛型类型需要使用class声明,而不是构造函数.那么keyof Type必须是匿名类型.您还需要键入properties,以便TypeScript知道它可以用keyof Type索引,在本例中,我给它一个Partial<Type>类型.

我还使用了一个类型断言,这样reduce的初始{}对象就被类型化为Partial<Type>,这样TypeScript就可以理解在创建之后如何对其进行索引.

class MyClass<Type> {
  properties: Partial<Type> = {};

  constructor(properties: Type) {
    this.properties = properties;
  }
  
  pick(...propNames: (keyof Type)[]) {
    return propNames.reduce((obj, name) => ({ 
      ...obj, 
      [name]: this.properties[name]
    }), {} as Partial<Type>);
  }
}

TypeScript Playground

Typescript相关问答推荐

如何使用泛型类型访问对象

Angular 信号:当输入信号改变值时,S触发取数的正确方式是什么?

与字符串文字模板的结果类型匹配的打字脚本

如何使用泛型自动推断TS中的类型

对未到达受保护路由的路由环境做出react

如何在深度嵌套的Reaction路由对象中隐藏父级?

在类型脚本中创建泛型类型以动态追加属性后缀

如何在使用条件类型时使用void

Typescript 中相同类型的不同结果

类型脚本-在调用期间解析函数参数类型

接受字符串或数字的排序函数

递归类型别名的Typescript 使用

如何将对象的字符串文字属性用作同一对象中的键类型

通过函数传递确切的类型,但验证额外的字段

无法使用prisma中的事务更新记录

如何根据Typescript 中带有泛型的对象嵌套键数组获取数组或对象的正确类型?

如何通过nx找到所有受影响的项目?

带有过滤键的 Typescript 映射类型

如何为字符串模板文字创建类型保护

在 next.js 13.4 中为react-email-editor使用forwardRef和next/dynamic的正确方法