首页 > 解决方案 > 具有泛型的打字稿初始化对象

问题描述

我想要的是这样的:

class ThemeExample <T> {
    static theme : T;
    static init(theme : T){
        ThemeExample.theme = theme;
    }
};

//config it 
ThemeExample.init({
    hello : 'hi'
})
//in another file access properties with auto completion
ThemeExample.theme.hello

但这不起作用。TS2302: Static members cannot reference class type parameters.

尝试了其他一些事情,例如在函数中创建类并返回它,并在类中使用泛型函数。仍然找不到让我初始化此配置一次的方法。然后稍后访问主题并自动完成其他文件中的所有属性。我需要这样的东西请帮助我,我太沮丧了。

标签: typescriptgenericstypestypescript-generics

解决方案


a 的静态部分class由类构造函数组成,并且只有一个这样的构造函数。它无法访问实例类型上的任何泛型参数,因为类构造函数需要能够为该泛型参数的任何可能规范创建实例。在您的ThemeExample<T>代码中,类构造函数必须能够创建ThemeExample<string>和的实例ThemeExample<number>。如果您可以拥有 type 的静态属性T,则意味着它必须同时是 astring和 anumber以及任何其他可能的类型T。它不起作用。

从概念上讲,您可以想象ThemeExample有一个static名为themetype的属性unknown,然后当您调用时ThemeExample.init("hello"),编译器会缩小类构造函数的范围,ThemeExample以便theme现在它是 typestring而不是unknown. 但是没有很好的机制来做到这一点。您可以想象编写类似断言函数的东西会产生这样的效果:

interface ThemeExampleConstructor<T = unknown> {
  theme: T;
  init<T>(theme: T): asserts this is ThemeExampleConstructor<T>;
  new(): ThemeExample<T>;
}

declare const ThemeExample: ThemeExampleConstructor;

ThemeExample.theme.toUpperCase(); // error
ThemeExample.init("hello");
ThemeExample.theme.toUpperCase(); // okay
new ThemeExample().instanceProp.toUpperCase(); // okay

但是你不能用class语法来做到这一点,即使你完成了这个,像这样的缩小也不能跨越文件边界甚至函数边界。没有任何机制可以让编译器在一个文件中看到在ThemeExample.init("hello")另一个文件中发生之前ThemeExample.theme.toUpperCase()。所以我们根本不能这样做。


相反,我建议采用产生新类构造函数的工厂函数的路线。该函数将存在于某个库中,例如Library/index.ts

export function initThemeExample<T>(theme: T) {
    return class ThemeExample {
        static theme = theme;
    };
}

然后在另一个文件(如userLib.ts)中,用户可以import从库中配置并重新导出:

import {initThemeExample} from './Library'

//config it 
export const ThemeExample = initThemeExample({
    hello: 'hi'
})

然后用户可以在所有其他文件中使用这个配置的构造函数:

import {ThemeExample} from './userLib'

//import your ThemeExaple in another file
document.write(ThemeExample.theme.hello.toUpperCase()); // HI

链接到 StackBlitz 代码


推荐阅读