是否可以从其泛型自动生成类属性?

时间:2019-10-24 14:59:05

标签: typescript typescript-generics

TypeScript中是否可以通过其通用类型生成具有如下属性的类:

class SomeClass<T> {
  // Read props from T somehow here?
}

interface Props {
  a: number;
  b: boolean;
}

const obj = new SomeClass<Props>;

// So now both obj.a and obj.b are available in autocomplete with correct types from Props interface

interface Props2 {
  some: string;
  other: number;
  props: boolean;
}

const obj2 = new SomeClass<Props2>;
// Now only three props from Props2 are available to obj2

我不想添加类似的内容

class SomeClass {
  [prop: string]: any
}

因为它将只允许在此处分配任何属性,而我想从泛型类型获得固定列表

2 个答案:

答案 0 :(得分:2)

您在这里寻找的是比标准继承更接近mixin的东西。但是interface X<T> extends Tare not supported by TypeScript通用混合。

您可以创建一个名为SomeClass的对象和一个名为SomeClass<T>的泛型类型,该类型可以使用某些类型断言来使用,但是会遇到一些限制。这是我的处理方式:

class _SomeClass<T> {
    constructor(t: T) {
        Object.assign(this, t);
    }
    // inside here we don't know about properties of T, though
    // so you'll have to do assertions
    get<K extends keyof T>(k: K): T[K] {
        return (this as any as T)[k]; // assertion
    }
}
type SomeClass<T> = T & _SomeClass<T>;
const SomeClass = _SomeClass as new <T>(t: T) => SomeClass<T>;

_SomeClass<T>是通用的,但本身并不知道实现T。构造函数将T对象中的属性分配给this(您需要类似此分配的内容才能在运行时获取有效的T)。在_SomeClass<T>实现内部,每次尝试访问Tthis的任何属性时都需要声明(因此this as any as Tthis as this & T是您的朋友)。

然后将类型SomeClass<T>定义为_SomeClass<T>T的{​​{3}},然后值SomeClass就是_SomeClass构造函数,但我们断言它的作用类似于SomeClass<T>构造函数。

让我们看看它是否有效:

interface Props {
    a: number;
    b: boolean;
}

const obj = new SomeClass<Props>({ a: 1, b: true });
console.log(obj.a); // 1
console.log(obj.get("a")); // 1

interface Props2 {
    some: string;
    other: number;
    props: boolean;
}

const obj2 = new SomeClass<Props2>({ some: "", other: 2, props: false });

可以使用您期望的IntelliSense进行编译。

当然还有局限性。 TypeScript实际上仅允许您extends个类,其中的键名是静态已知的。因此,如果您需要SomeClass的通用子类,那么您就不走运了:

class Nope<T> extends SomeClass<T> { // error!
/* Base constructor return type 'SomeClass<T>' is 
 not an object type or intersection of object types 
 with statically known members. */
}

一个具体的 子类将起作用(只要静态知道keyof T即可):

class Okay extends SomeClass<Props> {

}

好的,希望能有所帮助;祝你好运!

intersection

答案 1 :(得分:0)

映射的类型不能在类中使用。但是,在这里建立答案:https://stackoverflow.com/a/48345383/626911,您可以创建一个函数来创建一个对象,该对象的定义的属性与如下接口相匹配:

interface Props {
  a: number;
  b: boolean;
}

function build<T>(value?: T): T {
  return Object.assign({}, value);
}


const obj = build<Props>();
// obj contains typed a and b properties

// Or, pass in default values
// const obj = build<Props>({ a: 2, b: false });