【问题标题】:Passing namespace as generic将命名空间作为泛型传递
【发布时间】:2021-06-14 05:41:23
【问题描述】:

我在一个代码库中,它使用 typescript 在服务器(express)和 react 之间共享 API 接口合同。这些共享类型被组织到命名空间中,运行良好,但在 express 中可能有点冗长。

例如:

// Shared API type in global file
export namespace GetRecordAPI {
    export type PathParams = {
        recordId: string;
    };
    export type RequestBody = {};
    export type QueryParams = {
        date: string;
    };
    export type Response = APIResponseValidation & {
        record: RecordData;
    };
}

// Express route controller
type GetRecordHandler = RequestHandler<
  GetRecordAPI.PathParams, 
  GetRecordAPI.Response, 
  GetRecordAPI.RequestBody, 
  GetRecordAPI.QueryParams
>;
export const getRecord: GetRecordHandler = async (req, res, next) => {
    // ...
};

问题在于为每个快速路由控制器构造RequestHandler 变得非常冗长。由于所有内容都在命名空间中一致地组织,因此我非常希望有一个全局打字稿包装器,通过传递命名空间将它们拼接在一起。

// Global helper
type ExpressHandler<T> = RequestHandler<T.PathParams, T.Response, T.RequestBody, T.QueryParams>;


// Express route controller
export const getRecord: ExpressHandler<GetRecordAPI> = async (req, res, next) => {
    // ...
};

这样的事情还有可能吗? React 应用程序独立使用命名空间中的每个导出类型,因此目前最好保留此结构。

【问题讨论】:

  • 如果您可以将namespace 作为类型参数传递给泛型类型,这将很容易。不幸的是,我认为这是不可能的。你只会得到error: Cannot use namespace 'GetRecordAPI' as a type。我很想看看是否有人有解决方法!
  • 我认为没有运算符可以将类型从命名空间中提取出来。您可以将GetRecordAPI 重构为类似于interface 的东西,但是如果引用其他类型会更烦人,例如this。你也可以导出复合类型吗,比如this
  • 如果我写一个答案,我将不得不提及microsoft/TypeScript#9889microsoft/TypeScript#17588 以及其他几个相关问题(至少间接地)谈论无法以编程方式处理命名空间。跨度>
  • @jcalz 感谢您的示例。我已经开始转向复合类型,但是接口版本有一些优点,并且总体上定义更简洁。谢谢。

标签: typescript express namespaces typescript-generics


【解决方案1】:

我认为这是不可能的。您声明的命名空间是一个特殊的命名空间,其行为与普通命名空间不同。通常,命名空间会被转译为对象,并且可以用作值或类型。但是这个命名空间只导出类型,类型不会被转译,随后命名空间也不会。添加真实值也无济于事,因为任何显示所有键或类似内容的类型逻辑都不会影响类型,因为它们毕竟不是真实值。

playground

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-27
    • 1970-01-01
    • 1970-01-01
    • 2019-03-05
    • 2017-07-23
    相关资源
    最近更新 更多