版本:
我试图创建一堆模型类,每个类都有一些共同的属性。现在我想创建一个函数,该函数将使用通用类型输入操作该公共属性,该输入从任何模型获取实例。
简单(和工作)版本:
import { Set, Record } from 'immutable';
class Factory {}
class AnimalFactory extends Factory {
public static x: Set<{ id: string }> = Set([]);
}
class BeastFactory extends Factory {
public static x: Set<{ id: string }> = Set([]);
}
function getEntityId<T extends keyof TypeMap>(entity: T) {
const factory = TypeMap[entity];
factory.x.add({ id: 'id' })
}
type TypeMap = typeof TypeMap;
const TypeMap = {
a: AnimalFactory,
b: BeastFactory,
}
在getEntityId
中,您可以看到它接受ÀnimalFactory
或BeastFactory and attributes and methods inside the attributes all infer and merge the types of both classes, so that i can do
factory.x.add({id:&#39;&#39;})`完全输入。但我无法访问仅属于TypeMap的Classes子集的属性。
现在,当我试图将相同的概念应用于不可变记录时,它与上面的例子中的工作方式不同。
这是Record示例:
const animal2Defaults = {
foo: '',
x: Set<keyof IAnimalAttributes>([]),
};
export interface IAnimalAttributes {
foo?: string;
x?: Set<keyof IAnimalAttributes>;
}
class AnimalFactory2 extends Record<Required<IAnimalAttributes>>(animal2Defaults) {
public constructor(config: IAnimalAttributes) { super(config); }
}
const beast2Defaults = {
bar: '',
x: Set<keyof IBeastAttributes>([]),
};
interface IBeastAttributes {
bar?: string;
x?: Set<keyof IBeastAttributes>;
}
class BeastFactory2 extends Record<Required<IBeastAttributes>>(beast2Defaults) {
public constructor(config: IBeastAttributes) { super(config); }
}
function getEntityId2<T extends keyof TypeMap2>(entity: T, record: TypeMap2[T]) {
record.x.add('x'); // [ts] Cannot invoke an expression whose type lacks a
// call signature. Type '((value: "foo" | "x") => Set<"foo" | "x">) |
// ((value: "x" | "bar") => Set<"x" | "bar">)' has no compatible call signatures.
const unionRecord: TypeMapUnion = record;
unionRecord.x.add('x'); // [ts] Cannot invoke an expression whose type lacks a call signature.
// Type '((value: "foo" | "x") => Set<"foo" | "x">) | ((value: "x" | "bar") => Set<"x" | "bar">)' has no
// compatible call signatures.
// (property) add: ((value: "foo" | "x") => Set<"foo" | "x">) | ((value: "x" | "bar") => Set<"x" | "bar">)
const injectRecord: AttributeUnionRecords = record; // [ts]
// Type 'TypeMap2[T]' is not assignable to type 'AttributeUnionRecords'.
// Type 'AnimalFactory2 | BeastFactory2' is not assignable to type 'AttributeUnionRecords'.
// Type 'AnimalFactory2' is not assignable to type 'AttributeUnionRecords'.
// Type 'AnimalFactory2' is not assignable to type 'Record<Required<IAnimalAttributes> | Required<IBeastAttributes>> & Readonly<Required<IBeastAttrib...'.
if (record instanceof BeastFactory2) {
record.x.add('x')
}
}
function createInstance<T extends keyof TypeMap>(entity: T) {
const instance = new TypeMap2[entity]({}); // [ts] Cannot use 'new' with an expression whose type lacks a call or construct signature.
// (parameter) entity: T extends "a" | "b"
instance.x.add('x')
}
type AttributeUnion2 = Required<IBeastAttributes>;
type AttributeUnionRecords = Record<Required<IAnimalAttributes> | Required<IBeastAttributes>>
& Readonly<Required<IAnimalAttributes> | Required<IBeastAttributes>>;
type TypeMapUnion = AnimalFactory2 | BeastFactory2;
type TypeMap2 = {
a: AnimalFactory2,
b: BeastFactory2,
};
const TypeMap2 = {
a: AnimalFactory2,
b: BeastFactory2,
}
我遇到的问题是TS正在抛出的错误,请参阅上面的内联评论以了解错误。如果您知道如何解决或如何做到不同,请告诉我。