我需要创建一个名为Instantiate的强类型方法来接受任何类型的对象.

如果对象包含任何属性作为类,那么它将创建该类的实例,因此该对象属性的返回应该是该类的InstanceType

如果不是一个类,那它就保持原样.

我的问题是我不能写出正确的返回类型. 该值与原始对象的键不匹配.

请忽略方法Instantiate的主体/实现. 会照顾好我自己的.我只需要有正确的Typescript 就可以了.

以下是我到目前为止所try 的.

class Person {
    name!: "John Doe"
}

class Cat {
    scream!: "Help!!!"
}

const configApp = {
    isComplicated: true
}

const testData = {
    person: Person, 
    cat: Cat, 
    config: configApp,

} as const

type TClass = abstract new (...args: any) => any;
type TInstances<OBJ> = Record<
    keyof OBJ, 
    OBJ[keyof OBJ] extends TClass
        ? InstanceType<OBJ[keyof OBJ]>
        : OBJ[keyof OBJ]
>;

const instantiate = <T ,>(obj:T): TInstances<T> => { return {} as any}

// Below should not error
const result = instantiate(testData);
result.person.name; //  Error
result.cat.scream;  // Error
result.config.isComplicated; // Error

Playground

推荐答案

听起来你想让instantiate拥有以下类型:

declare const instantiate: <T extends object>(obj: T) =>
    { [K in keyof T]: T[K] extends new () => infer I ? I : T[K] }

返回类型是T的属性之上的mapped type,其中通过conditional type判断每个属性类型是否可以用作无参数构造函数.如果不是,则保留属性类型不变;否则,将其替换为其实例类型(属性类型中的inferred).

这为您提供了您想要的示例:

const result = instantiate(testData);
/* const result: {
    readonly person: Person;
    readonly cat: Cat;
    readonly config: {
        isComplicated: boolean;
    };
} */

所以这就是问题的答案.


请注意,实际上正确地使用implementinginstantiate是很难做到正确的.在运行时,您需要以某种方式查看任意值并确定它是否是无参数构造函数,这样您可能就可以编写new value()来获取实例.但是,没有一种真正安全的方法来确定某个东西是否是构造函数.您可以判断一个值是否为函数,以及它的length property是否为零,但并不是所有的函数都可以作为构造函数调用(例如,arrow functions),也不是所有可以这样调用的函数都是intended用作构造函数.请参见How to check if a Javascript function is a constructor.如果有人打来电话

const hmm = instantiate({ a: () => 1 })
//    ^? const hmm: {a: () => 1}

那么我给出的调用签名将显示hmm.a是一个函数,但是在运行时,谁知道会发生什么.这一切都取决于你的instantiate.instantiate的简单实现很可能会出现运行时错误.

这些可能是你不关心的边缘 case ,但你至少应该意识到它们.

Playground link to code

Typescript相关问答推荐

在这种情况下,如何获得类型安全函数的返回值?

如何在函数参数中使用(或模仿)`success`的行为?

有没有一种方法可以在保持类型的可选状态的同时更改类型?

typescribe警告,explate—deps,useEffect依赖项列表

打字脚本中泛型和直接类型重新映射的不同行为

将具有Readonly数组属性的对象接口转换为数组

是否可以判断某个类型是否已合并为内部类型?

常量类型参数回退类型

有没有一种方法可以确保类型的成员实际存在于TypeScript中的对象中?

创建依赖函数参数的类型

为什么上下文类型在`fn|curred(Fn)`的联合中不起作用?

在正常函数内部调用异步函数

为什么发送空字段?

如何键入派生类的实例方法,以便它调用另一个实例方法?

如何在Next.js和Tailwind.css中更改悬停时的字体 colored颜色

将类型脚本函数返回类型提取到VSCode中的接口

为什么`map()`返回类型不能维护与输入相同数量的值?

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

有没有办法将类型与关键更改相匹配?

node_modules/@newrelic/native-metrics:命令失败. node_modules/couchbase:命令失败.退出代码:127