정의 파일 (* d.ts)의 가져 오기 클래스


104

세션 저장소에서 사용자 지정 데이터를 사용할 수 있도록 Express 세션 유형을 확장하고 싶습니다. 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) : "";
    }
}

그래서 own.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;
    }
}

그리고 테스트 필드가 정상적으로 작동하므로 가져 오기로 인해 문제가 발생합니다.

또한 /// <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 Sesion을 확장하기위한 자체 타이핑 파일 :

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

그러나 import 문을 맨 위에 올릴 때 여전히 작동하지 않습니다. 어떤 아이디어?

답변:


295

2 년 간의 TypeScript 개발 끝에 마침내이 문제를 해결할 수있었습니다.

기본적으로 TypeScript에는 "로컬"(일반 모듈) 및 주변 (전역)의 두 가지 종류의 모듈 유형 선언이 있습니다. 두 번째 종류는 기존 모듈 선언과 병합되는 전역 모듈 선언을 작성할 수 있습니다. 이 파일의 차이점은 무엇입니까?

d.ts파일은 가져 오기가없는 경우에만 앰비언트 모듈 선언으로 처리됩니다. 가져 오기 행을 제공하면 이제 전역 파일이 아닌 일반 모듈 파일로 처리되므로 모듈 정의를 보강 할 수 없습니다.

그래서 여기서 논의한 모든 솔루션이 작동하지 않습니다. 하지만 다행스럽게도 TS 2.9 이후 import()구문을 사용하여 유형을 전역 모듈 선언으로 가져올 수 있습니다 .

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

그래서 라인 import("./user").User;이 마술을하고 이제 모든 것이 작동합니다. :)


4
이 타이프의 최신 버전으로, 적어도 그것을 할 올바른 방법입니다
제퍼슨 타바레스

1
이 접근 방식은 Node의 process객체 와 같은 전역 모듈을 확장하는 인터페이스를 선언 할 때 이상적인 솔루션 입니다.
Teffen Ellis

2
감사합니다. 이것이 Express Middleware 확장으로 내 문제를 해결하는 유일한 명확한 답변이었습니다!
Katsuke

2
@ Michał Lytek 감사합니다.이 접근 방식에 대한 공식 문서 참조가 있는지 궁금합니다.
Gena


5

최신 정보

typescript 2.9부터는 유형을 전역 모듈로 가져올 수있는 것 같습니다. 자세한 내용은 허용 된 답변을 참조하십시오.

원래 답변

당신이 직면하고있는 문제는 모듈 선언강화한 다음 클래스 타이핑에 관한 것이라고 생각합니다 .

이것을 컴파일하면 알 수 있듯이 내보내기는 괜찮습니다.

// app.ts  
import { User } from '../models/user'
let theUser = new User('theLogin', 'thePassword')

의 모듈 선언을 보강하려는 것 같 Express으며 정말 가깝습니다. 이것은 트릭을 수행해야합니다.

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

그러나이 코드의 정확성은 명시 적 선언 파일의 원래 구현에 따라 다릅니다.


import 문을 내부로 이동하면 오류가 발생 Import declarations in a namespace cannot reference a module.합니다.. 코드를 복사하여 붙여 넣으면 Import or export declaration in an ambient module declaration cannot reference module through relative module name.. 그리고 비 상대 경로를 사용하려고하면 파일을 찾을 수 없으므로 선언 폴더를 node_modules ad add path로 이동 "declarations/models/user"했지만 여전히 전체 d.ts가 작동하지 않습니다. 인텔리 센스에서 Express 세션의 자체 확장을 볼 수 없습니다 또는 tsc.
Michał Lytek

이 오류에 익숙하지 않습니다. 죄송합니다. 설정에 다른 것이 있습니까? 이것이 당신을 위해 컴파일합니까? gist.github.com/pellejacobs/498c997ebb8679ea90826177cf8a9bad .
Pelle Jacobs

이런 식으로 작동하지만 실제 앱에서는 여전히 작동하지 않습니다. 나는 세션 객체가 명시 적 요청 객체를 가지고 있고 그것은 다른 유형 선언 - 네임 스페이스 Express에서 모듈하지 '표현' github.com/DefinitelyTyped/DefinitelyTyped/blob/master/...
마이클 Lytek

5
나에게도 작동하지 않습니다. 내 tsd.d.ts 파일에 import 문을 추가하면 전체 파일이 작동을 멈 춥니 다. (그 파일에 정의 된 것들에 대한 내 응용 프로그램의 나머지 부분에서 에러가 발생.)
베른 젠슨에게

5
나는 같은 문제가 있었다. .d.ts 내에서 선언 된 모듈에서 가져 오기를 사용하면 작동합니다. declare module 'myModule' {import { FancyClass } from 'fancyModule'; export class MyClass extends FancyClass {} }
zunder

4

Michał Lytek의 답변에 감사드립니다 . 내 프로젝트에서 사용한 또 다른 방법이 있습니다.

우리는 어디에나 쓰지 않고 여러 번 가져 User오고 재사용 할 수 import("./user").User있으며 확장 하거나 다시 내보낼 수도 있습니다.

declare namespace Express {
  import("./user");  // Don't delete this line.
  import { User } from "./user";

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

  export class SuperUser extends User {
    superPower: string;
  }

  export { User as ExpressUser }
}

재미있게 보내세요 :)


0

그것은 단지와 논리를 수행 할 수 없습니다 express-session:

own.d.ts:

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

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

메인에서 index.ts:

import express from 'express';
import session from 'express-session';
import own from './types/own';

const app = express();
app.get('/', (req, res) => {
    let username = req!.session!.user.login;
});

적어도 이것은 문제없이 컴파일되는 것 같습니다. 전체 코드는 https://github.com/masa67/so39040108을 참조 하십시오.


1
선언 파일을 tsc컴파일 하지 않으므로 가져 오지 않아야합니다. 그들은 출력의 편집에 아닌 것으로 의미
발린 Csak을
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.