我想扩展快速会话类型,以允许在会话存储中使用自定义数据。我有一个对象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) : "";
}
}
所以我创建了自己的n.d.ts文件来合并现有的快速会话类型的定义:
import { User } from "./models/user";
declare module Express {
export interface Session {
user: User;
}
}
但它根本不工作- VS Code和tsc看不到它。所以我用简单的类型创建了测试定义:
declare module Express {
export interface Session {
test: string;
}
}
测试域工作正常,所以导入会导致问题。
我还尝试添加/// <reference path='models/user。ts'/>代替导入,但tsc没有看到User类-我怎么能在*d中使用我自己的类。ts文件?
编辑:
我设置tsc在编译时生成定义文件,现在我有了我的user.d.ts:
export declare class User {
login: string;
hashedPassword: string;
constructor();
constructor(login: string, password: string);
}
以及用于扩展Express session的自己的打字文件:
import { User } from "./models/user";
declare module Express {
export interface Session {
user: User;
uuid: string;
}
}
但是当import语句在顶部时仍然不工作。什么好主意吗?
为了完整起见:
如果你有一个环境模块声明(即,没有任何顶级导入/导出),它是全局可用的,不需要显式地将它导入到任何地方,但如果你有一个模块声明,你将需要在消费者文件中导入它。
如果你想在你的环境模块声明中导入一个现有的类型(它是从其他文件导出的),你不能用顶级导入(因为那样它就不是环境声明了)。
如果你这样做:
(https://stackoverflow.com/a/39132319/2054671)
// index.d.ts
import { User } from "./models/user";
declare module 'express' {
interface Session {
user: User;
uuid: string;
}
}
这将用这个新接口扩充现有的“express”模块。https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation
但是要使用这个,你必须在你的消费者文件中导入这个,它不会像环境声明一样默认全局可用,因为它不再是一个环境声明
so, to import an existing type exported from another file, you have to import it inside the declare block (talking about this example, in other examples where you are not declaring a module, you can import inline at other places)
to do this, you cannot use a regular import like this
declare module B {
import A from '../A'
const a: A;
}
because in current implementation, the rules for resolution of this imported module are confusing, and hence ts does not allow this. This is the reason for the error Import or export declaration in an ambient module declaration cannot reference module through relative module name.
(I am not able to find the link to the relevant github issue, if someone finds it, please edit this answer and mention. https://github.com/microsoft/TypeScript/issues/1720)
Please note, you can still do something like this:
declare module B {
import React from 'react';
const a: A;
}
because this is an absolute path import and not a relative path import.
so the only way to correctly do this in an ambient module is using the dynamic import syntax (https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-9.html#import-types)
declare namespace Express {
interface Request {
user: import("./user").User;
}
}
as mentioned in the accepted answer (https://stackoverflow.com/a/51114250/2054671)
you can also do a global augmentation with something like this:
import express = require('express');
import { User } from "../models/user";
declare global {
namespace Express {
interface Session {
user: User;
uuid: string;
}
}
}
but remember global augmentation is only possible in a module not an ambient declaration, so this would work only if you import it in the consumer file, as mentioned in @masa's answer (https://stackoverflow.com/a/55721549/2054671)
以上所有要点都适用于导入从其他地方导出的模块,在您的环境模块中,但是在另一个环境模块中导入一个环境模块呢?(如果你想在你自己的环境模块声明中使用一个现有的环境声明,并确保这些环境类型在你的环境模块的消费者中也可见,这是很有帮助的)
你可以使用/// <引用类型="../.. "/a" />指令
/ / ambientA.d.ts
接口A {
t:字符串
}
/ / ambientB.d.ts
/// <引用类型="../ambientA.d. "ts " / >
声明模块B {
a: a;
导出{a};
}
其他相关答案的链接:
在TypeScript中使用导入的类型进行环境声明