当前位置: 首页 > 知识库问答 >
问题:

在定义文件中导入类(*d.ts)

简滨海
2023-03-14

我想扩展快速会话类型以允许在会话存储中使用我的自定义数据。我有一个对象req.session.user,它是我的类User的实例:

export class User {
    public login: string;
    public hashedPassword: string;

    constructor(login?: string, password?: string) {
        this.login = login || "" ;
        this.hashedPassword = password ? UserHelper.hashPassword(password) : "";
    }
}

所以我创建了自己的。d、 ts文件以将定义与现有express会话类型合并:

import { User } from "./models/user";

declare module Express {
    export interface Session {
        user: User;
    }
}

但是它根本不起作用——VS Code和tsc看不到它。所以我用简单的类型创建了测试定义:

declare module Express {
    export interface Session {
        test: string;
    }
}

并且测试场工作正常,所以导入导致问题。

我还尝试添加<代码>///

编辑:我设置tsc在编译时生成定义文件,现在我有了我的user.d.ts:

export declare class User {
    login: string;
    hashedPassword: string;
    constructor();
    constructor(login: string, password: string);
}

以及用于扩展Express Sesion的自己的键入文件:

import { User } from "./models/user";
declare module Express {
    export interface Session {
        user: User;
        uuid: string;
    }
}

共有3个答案

阳博赡
2023-03-14

为了完整起见:

  • 如果您有一个环境模块声明(即,没有任何顶级导入/导出),它在全球范围内可用,而无需在任何地方显式导入,但如果您有一个模块声明,则需要将其导入到使用者文件
  • 如果要在环境模块声明中导入现有类型(从其他文件导出),则不能使用顶级导入(因为这样它就不会保持为环境声明)

所以如果你这样做:(https://stackoverflow.com/a/39132319/2054671)

// index.d.ts
import { User } from "./models/user";
declare module 'express' {
  interface Session {
    user: User;
    uuid: string;
  }
}

这将用这个新接口来增强现有的“快速”模块。https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation

但要使用它,您必须将其导入到您的消费者文件中,默认情况下,它不会像环境声明一样全局可用,因为它不再是环境声明

>

为此,您不能使用这样的常规导入

declare module B {
  import A from '../A'
  const a: A;
}

因为在当前实现中,这个导入模块的解析规则令人困惑,因此ts不允许这样做。这就是环境模块声明中错误导入或导出声明无法通过相对模块名称引用模块的原因。(我找不到相关github问题的链接,如果有人找到了,请编辑此答案并提及。https://github.com/microsoft/TypeScript/issues/1720)

请注意,您仍然可以这样做:

declare module B {
  import React from 'react';
  const a: A;
}

因为这是绝对路径导入,而不是相对路径导入。

因此,在环境模块中正确执行此操作的唯一方法是使用动态导入语法(https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-9.html#import-types)

declare namespace Express {
 interface Request {
   user: import("./user").User;
 }
}

如公认答复(https://stackoverflow.com/a/51114250/2054671)所述

您还可以通过以下方式进行全局增强:

import express = require('express');
import { User } from "../models/user";

declare global {
    namespace Express {
        interface Session {
            user: User;
            uuid: string;
        }
    }
}

但是请记住,全局增强只在模块中可能,而不是在环境声明中,因此只有当您将其导入到消费者文件中时,这才有效,如@masa的回答中所述(https://stackoverflow.com/a/55721549/2054671)

以上几点都适用于导入从其他地方导出的模块,在您的环境模块中,但是在另一个环境模块中导入环境模块呢?(如果您想在自己的环境模块声明中使用现有的环境声明并确保这些环境类型在环境模块的使用者中也可见,这很有帮助)

>

// ambientA.d.ts
interface A {
  t: string
}
// ambientB.d.ts
/// <reference types="../ambientA.d.ts" />
declare module B {
  const a: A;
  export { a };
}

其他相关答案的链接:

  • 在TypeScript中导入类型的环境声明
宗政松
2023-03-14

感谢MichałLytek的回答。这是我在项目中使用的另一种方法。

我们可以导入User并多次重用,而无需编写导入("./user")。用户无处不在,甚至实现它或重新导出它。

declare namespace Express {
    type User = import('./user').User;

    export interface Request {
        user: User;
        target: User;
        friend: User;
    }

    export class SuperUser implements User {
        superPower: string;
    }

    export { User as ExpressUser }
}

玩得开心:)

陆子默
2023-03-14

经过两年的TypeScript开发,我终于解决了这个问题。

基本上,TypeScript有两种模块类型声明:“本地”(普通模块)和环境(全局)。第二种允许编写与现有模块声明合并的全局模块声明。这个文件有什么区别?

d.ts文件仅在没有任何导入时才被视为环境模块声明。如果您提供导入行,它现在被视为普通模块文件,而不是全局文件,因此扩充模块定义不起作用。

这就是我们在这里讨论的所有解决方案都不起作用的原因。但幸运的是,从TS 2.9开始,我们能够使用import()语法将类型导入全局模块声明:

declare namespace Express {
  interface Request {
    user: import("./user").User;
  }
}

因此,行导入(“/用户”)。用户 变魔术了,现在一切都正常了:)

 类似资料:
  • 我需要帮助来找出如何解决活动中两个相互冲突的导入的问题,即: null 取决于哪一个先来。

  • 问题内容: 我是Java的新手,但我一直在网上寻找解决方案,但似乎都没有用。请帮我。 我有两个文件。其中之一是包含主要功能的java文件。在里面: 使用该命令,我想创建一个新对象,该对象是一个名为的单独文件中的类。但是Java无法识别VaporVisitor是什么,大概是因为它不知道存在(它在同一目录中)。我试图使它们成为同一程序包的一部分,放入不同的程序包中并导入…,但所有这些都失败了。谁能给我

  • 问题内容: package scanner; 为什么会收到一条错误消息,提示“ import java.util.Scanner”与同一文件中定义的文件冲突? 问题答案: 您自己的类名为,并且您正在导入另一个名为的类。这意味着在创建type变量时,编译器不知道您指的是哪个类。 尝试将您的班级重命名为其他名称。 另外,您可以使用这种方式而不重命名自己的类:

  • 问题内容: 如何导入在其他文件中编写的类?我所有的课程都在同一个程序包下。 问题答案: 如果所有类都在同一个程序包中,则无需导入它们。 只需像这样实例化该对象:

  • 问题内容: 假设我们项目中的每个PHP文件都包含一个类定义,那么如何确定文件中定义了哪些类? 我知道我可以对文件进行正则表达式声明,但是我更喜欢做一些更有效的事情。 问题答案: 对于正在从事的项目,我需要这样的东西,这是我编写的功能:

  • 问题内容: 我正在尝试组织一些模块供我自己使用。我有这样的事情: 在中,如果要导入lib,我想定义一些要使用的类。但是,如果不将这些类分离到文件中并将其导入中,我似乎无法弄清楚。 与其说: 我想要这样的东西: 有可能吗,还是我必须将类分成另一个文件? 编辑 好的,如果我从另一个脚本导入lib,则可以访问Helper类。如何从settings.py访问Helper类? 此处的示例描述了包装内参考。我