Typescript를 사용하여 Express Request 개체 확장
타이프 스크립트를 사용하여 미들웨어에서 요청 개체를 표현하기 위해 속성을 추가하려고 합니다.그러나 개체에 추가 속성을 추가하는 방법을 찾을 수 없습니다.가능하면 괄호 표기법은 사용하지 않았으면 합니다.
다음과 같은 내용을 쓸 수 있는 솔루션을 찾고 있습니다(가능한 경우).
app.use((req, res, next) => {
req.property = setProperty();
next();
});
사용자 정의 정의를 만들고 Typescript의 Declaration Merge(선언 병합) 기능을 사용합니다.이것은, 예를 들면, 에서 자주 사용됩니다.
" " " 를 만듭니다.custom.d.ts
꼭 이 을 담으세요.tsconfig.json
의 »files
- 경우). - 섹션(있는 경우)을 사용하다
declare namespace Express {
export interface Request {
tenant?: string
}
}
이를 통해 코드의 임의의 시점에서 다음과 같은 것을 사용할 수 있습니다.
router.use((req, res, next) => {
req.tenant = 'tenant-X'
next()
})
router.get('/whichTenant', (req, res) => {
res.status(200).send('This is your tenant: '+req.tenant)
})
의 코멘트에서 제시된 바와 같이 단순히 글로벌에 선언합니다.Express
이름 공간을 지정합니다.§:
declare global {
namespace Express {
interface Request {
context: Context
}
}
}
완전한 예:
import * as express from 'express';
export class Context {
constructor(public someContextVariable) {
}
log(message: string) {
console.log(this.someContextVariable, { message });
}
}
declare global {
namespace Express {
interface Request {
context: Context
}
}
}
const app = express();
app.use((req, res, next) => {
req.context = new Context(req.url);
next();
});
app.use((req, res, next) => {
req.context.log('about to return')
res.send('hello world world');
});
app.listen(3000, () => console.log('Example app listening on port 3000!'))
더
글로벌 네임스페이스의 확장에 대해서는, TypeScript Deep Dive 를 참조해 주세요.
버전의 express의 express를 .express-serve-static-core
★★★★★★ 。
이것은 Express 객체가 https://github.com/DefinitelyTyped/DefinitelyTyped/blob/8fb0e959c2c7529b5fa4793a44b41b797ae671b9/types/express/index.d.ts#L19 에서 생성되었기 때문에 필요합니다.
기본적으로 다음 항목을 사용합니다.
declare module 'express-serve-static-core' {
interface Request {
myField?: string
}
interface Response {
myField?: string
}
}
8개 정도의 답을 시도했지만 성공하지 못했다.3mards repo를 가리키는 jd291의 코멘트로 겨우 작업을 할 수 있었습니다.
.types/express/index.d.ts
이치노릇을 하다
declare namespace Express {
interface Request {
yourProperty: <YourType>;
}
}
and에 포함하다.tsconfig.json
라이선스:
{
"compilerOptions": {
"typeRoots": ["./types"]
}
}
★★★★★★★★★★★★★★★.yourProperty
모든 요청에 따라 접근 가능해야 합니다.
import express from 'express';
const app = express();
app.get('*', (req, res) => {
req.yourProperty =
});
(다른 사람들과 마찬가지로) 받아들여진 답변은 나에게 통하지 않지만
declare module 'express' {
interface Request {
myProperty: string;
}
}
누군가 도움이 됐으면 좋겠네요
제시된 솔루션 중 어느 것도 제게는 효과가 없었습니다.결국 Request 인터페이스를 확장하게 되었습니다.
import {Request} from 'express';
export interface RequestCustom extends Request
{
property: string;
}
사용 방법:
import {NextFunction, Response} from 'express';
import {RequestCustom} from 'RequestCustom';
someMiddleware(req: RequestCustom, res: Response, next: NextFunction): void
{
req.property = '';
}
편집: tsconfig에 따라서는, 다음의 방법으로 실시할 필요가 있는 경우가 있습니다.
someMiddleware(expressRequest: Request, res: Response, next: NextFunction): void
{
const req = expressRequest as RequestCustom;
req.property = '';
}
대체 솔루션
이것은 실제로 질문에 직접적으로 대답하는 것은 아니지만, 저는 대안을 제시하고 있습니다.같은 문제로 고민하고 있었는데, 이 페이지의 거의 모든 인터페이스 확장 솔루션을 사용해 보았지만, 어느 것도 효과가 없었습니다.
"왜 실제로 요청 개체를 수정하는 거지?"라는 생각이 들었습니다.
response.locals
익스프레스 개발자들은 사용자가 자신의 속성을 추가하고 싶어할 수 있다고 생각한 것 같습니다.locals
물건.함정은, 그것이 그 안에 있지 않다는 것이다.request
,에서는response
★★★★★★ 。
response.locals
오브젝트에는 요구와 응답 사이클에 캡슐화되어 다른 사용자의 다른 요구에 노출되지 않는 임의의 커스텀속성을 포함할 수 있습니다.
userId를 ? ★★★★★★★★★★를 설정해 주세요.response.locals.userId = '123'
는 없습니다. 타이핑과 씨름할 필요가 없습니다.
단점은 응답 개체를 전달해야 한다는 것입니다. 그러나 이미 이 개체를 전달하고 있을 가능성이 높습니다.
https://expressjs.com/en/api.html#res.locals
타자 치기
또 다른 단점은 안전성이 떨어진다는 것이다.하여 ''할 수 있습니다.body
및locals
★★★★★★★★★★★★★★★★★★:
Response<MyResponseBody, MyResponseLocals>
https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/express/index.d.ts#L127
주의사항
userId 속성이 실제로 존재한다고 보장할 수 없습니다.특히 객체가 있는 경우 액세스하기 전에 확인해야 할 수 있습니다.
위의 예를 사용하여 userId를 추가하면 다음과 같은 결과를 얻을 수 있습니다.
interface MyResponseLocals {
userId: string;
}
const userMiddleware = (
request: Request,
response: Response<MyResponseBody, MyResponseLocals>,
next: NextFunction
) => {
const userId: string = getUserId(request.cookies.myAuthTokenCookie);
// Will nag if you try to assign something else than a string here
response.locals.userId = userId;
next();
};
router.get(
'/path/to/somewhere',
userMiddleware,
(request: Request, response: Response<MyResponseBody, MyResponseLocals>) => {
// userId will have string type instead of any
const { userId } = response.locals;
// You might want to check that it's actually there
if (!userId) {
throw Error('No userId!');
}
// Do more stuff
}
);
2021년에는 이것이 유효합니다.
express 4.17.1에서는 https://stackoverflow.com/a/55718334/9321986과 https://stackoverflow.com/a/58788706/9321986의 조합이 다음과 같이 동작했습니다.
types/express/index.d.ts
:
declare module 'express-serve-static-core' {
interface Request {
task?: Task
}
}
및에tsconfig.json
:
{
"compilerOptions": {
"typeRoots": ["./types"]
}
}
이 모든 응답은 어떤 면에서 잘못되었거나 시대에 뒤떨어진 것으로 보인다.
2020년 5월에는 이 방법이 효과가 있었습니다.
${PROJECT_ROOT}/@types/express/index.d.ts
:
import * as express from "express"
declare global {
namespace Express {
interface Request {
my_custom_property: TheCustomType
}
}
}
tsconfig.json
, 하다, 하다, 하다, 하다, 하다와
"typeRoots": [ "@types" ]
건배.
이것은 매우 오래된 질문이지만, 나는 최근에 이 문제를 우연히 발견했다.하지만, 했습니다.Request
로, 코 、 - 、 - 、 - 、 - 、 - 、 - 、 - - - - - - 。논리적으로, 나는 이것을 시도했다.
import ITenant from "../interfaces/ITenant";
declare namespace Express {
export interface Request {
tenant?: ITenant;
}
}
가 취급하기 때문에 효과가 없었습니다..d.ts
파일은 글로벌 Import로 간주되며 Import가 있는 경우 일반 모듈로 취급됩니다.그렇기 때문에 위의 코드는 표준 타이프스크립트 설정으로 동작하지 않습니다.
결국 이렇게 된 거야
// typings/common.d.ts
declare namespace Express {
export interface Request {
tenant?: import("../interfaces/ITenant").default;
}
}
// interfaces/ITenant.ts
export interface ITenant {
...
}
이것은 Nestjs와 Express를 사용할 때 효과가 있었습니다.2020년 11월 현재.
./@types/express-serve-static-core/index.d.ts 파일을 만듭니다.
참고: 위의 경로와 파일 이름이 정확하게 있어야 합니다.그러면 Typescript 선언 마지가 작동합니다.
import { UserModel } from "../../src/user/user.model";
declare global{
namespace Express {
interface Request {
currentUser: UserModel
}
}
}
이것을 tsconfig.json에 추가합니다.
"typeRoots": [
"@types",
"./node_modules/@types",
]
express4에 대응한 솔루션을 찾고 있는 경우는, 이하를 참조해 주세요.
@types/sys/index.d.ts: -----------------------------------------------------
declare namespace Express { // must be namespace, and not declare module "Express" {
export interface Request {
user: any;
}
}
tsconfig.json:
{
"compilerOptions": {
"module": "commonjs",
"target": "es2016",
"typeRoots" : [
"@types", // custom merged types must be first in a list
"node_modules/@types",
]
}
}
https://github.com/TypeStrong/ts-node/issues/715#issuecomment-526757308에서 레퍼런스
TypeScript에서는 인터페이스는 오픈엔드로 되어 있습니다.즉, 속성을 재정의하는 것만으로 어디에서나 속성을 추가할 수 있습니다.
이 express.d.ts 파일을 사용하고 있는 것을 고려하면 Request 인터페이스를 재정의하여 추가 필드를 추가할 수 있습니다.
interface Request {
property: string;
}
미들웨어 기능에서는 req 파라미터에도 이 속성이 있어야 합니다.코드를 변경하지 않고 사용할 수 있습니다.
패키지에 하는 사용자에게 합니다.ts-node
.
저도 요청 오브젝트 확장과 같은 고민에 시달리고 있었습니다.스택 오버플로우에서 많은 답변을 따라다니다가, 이하와 같은 전략을 따르는 것으로 끝납니다.
다음 디렉토리에서 express에 대한 확장 타이핑을 선언했습니다. ${PROJECT_ROOT}/api/@types/express/index.d.ts
declare namespace Express {
interface Request {
decoded?: any;
}
}
.tsconfig.json
이런 거에 대해서요.
{
"compilerOptions": {
"typeRoots": ["api/@types", "node_modules/@types"]
...
}
}
을 멈췄습니다만,도 「아쉽게도」, 「아쉽게도」, 「아쉽게도」, 「아쉽다」, 「아쉽다」, 「아쉽다」, 「아쉽다」, 「아쉽다」, 「아쉽다」, 「아쉽다」,ts-node
컴파일러는 여전히 던지곤 합니다.
Property 'decoded' does not exist on type 'Request'.
그...ts-node
요청 객체의 확장 유형 정의를 찾을 수 없었습니다.
시간 후 타이핑 수 은 VS 코드가 입니다.이것은, 에 문제가 있는 것을 나타내고 있습니다.ts-node
컴파일러
start (업데이트 시작)script
package.json
쳐주주고
"start": "ts-node --files api/index.ts",
--files
여기서 인수는 커스텀유형 정의를 결정하는 중요한 역할을 합니다.
상세한 것에 대하여는, https://github.com/TypeStrong/ts-node#help-my-types-are-missing 를 참조해 주세요.
Request type을 글로벌하게 확장하지 않고 새로운 type을 생성하여 이 문제를 해결했습니다.
import { Request } from 'express'
type CustomRequest = Request & { userId?: string }
'No overload match this call' 오류가 발생하지 않도록 하려면 옵션(?) 연산자와 함께 확장 속성을 사용해야 합니다.
패키지 버전:
"@types/express": "^4.17.13",
"@types/morgan": "^1.9.3",
"@types/node": "^17.0.29",
"typescript": "^4.6.3",
"express": "^4.18.0",
가능한 해결책 중 하나는 "모든 것에 이중 주조"를 사용하는 것입니다.
1- 속성과의 인터페이스를 정의합니다.
export interface MyRequest extends http.IncomingMessage {
myProperty: string
}
더블 캐스트
app.use((req: http.IncomingMessage, res: http.ServerResponse, next: (err?: Error) => void) => {
const myReq: MyRequest = req as any as MyRequest
myReq.myProperty = setProperty()
next()
})
더블 캐스팅의 장점은 다음과 같습니다.
- 타이핑 사용 가능
- 기존 정의를 오염시키지 않고 확장하여 혼란을 방지한다.
- 명시적이기 을 with팅이 since팅이 、 since since 、 since since 、 since since 、 since since since since since since since since since 。
-noImplicitany
또는 퀵(입력되지 않은) 루트가 있습니다.
req['myProperty'] = setProperty()
(기존 정의 파일을 자신의 속성으로 편집하지 마십시오.유지관리가 불가능합니다.정의가 잘못된 경우 풀 요청을 엽니다.)
편집
은 아래해 주세요.이 경우는 간단한 캐스팅이 가능합니다.req as MyRequest
여기서 다른 것을 찾고 있는 사람들을 돕는 것이 익스프레스를 확장하려고 했던 2020년 5월 말에 나에게 효과가 있었다.JS의 요구.저는 이 작업을 수행하기 전에 수십 가지 이상의 시도를 해야 했습니다.
- tsconfig.json의 "typeRoots"에서 모든 사용자가 권장하는 순서를 바꿉니다(TSconfig에 ".src" 등의 rootDir 설정이 있는 경우 src 패싱을 삭제하는 것을 잊지 마십시오).예:
"typeRoots": [
"./node_modules/@types",
"./your-custom-types-dir"
]
- 커스텀 확장자('/your-custom-types-dir/express/index.d.ts")의 예.내 경험에서 클래스를 유형으로 사용하려면 인라인 Import 및 기본 내보내기를 사용해야 했습니다.이것도 마찬가지입니다.
declare global {
namespace Express {
interface Request {
customBasicProperty: string,
customClassProperty: import("../path/to/CustomClass").default;
}
}
}
- nodeemon.json 파일을 업데이트하여 "--files" 명령을 ts-node에 추가합니다.예:
{
"restartable": "rs",
"ignore": [".git", "node_modules/**/node_modules"],
"verbose": true,
"exec": "ts-node --files",
"watch": ["src/"],
"env": {
"NODE_ENV": "development"
},
"ext": "js,json,ts"
}
모든 답을 시도해 봤지만 제대로 작동하지 않았다면, 여기 간단한 해킹이 있습니다.
app.use((req, res, next) => {
(req as any).property = setProperty();
next();
});
하면 ★★★★★★★★★★★★★★★★★★★★▼req
any
따라서 원하는 속성을 추가할 수 있습니다..req
★★★★★★ 。
같은 문제가 있어 다음과 같이 해결합니다.
// /src/types/types.express.d.ts
declare namespace Express {
export interface Request {
user: IUser
}
}
하지만 몇 가지 조건이 필요합니다!
- 가가에
tsconfig.json
"paths": {
"*": [
"node_modules/*",
"src/types/*"
]
},
후에 ★★★★tsc
만, 「번들」은,ts-node
- 붙여야 요.
--files
컴파일러
ts-node --files src/server.ts
과 같은 인터페이스가 일 수 한 속성을 할 수 .그러기 위해서는 '키를.다른 답변과 같은 인터페이스가 너무 제한적일 수 있습니다만, 실제로는 필요한 속성을 유지하고, 다음에 추가할 속성을 추가할 수 있습니다.string
이 「」인 any
import { Request, Response, NextFunction } from 'express'
interface IRequest extends Request {
[key: string]: any
}
app.use( (req: IRequest, res: Response, next: NextFunction) => {
req.property = setProperty();
next();
});
이제 이 개체에 원하는 속성을 추가할 수도 있습니다.
간단한 해결책은 express request를 확장하는 새로운 커스텀인터페이스를 만드는 것입니다.이 인터페이스에는 옵션으로 모든 커스텀 요구 속성이 포함되어 있어야 합니다.이 인터페이스를 미들웨어 요구 유형으로 설정합니다.
// ICustomRequset.ts
import { Request } from "express"
export default interface ICustomRequset extends Request {
email?: string;
roles?: Array<string>;
}
// AuthMiddleware.ts
...
export default async function (
req: ICustomRequset,
res: Response,
next: NextFunction
) {
try {
// jwt code
req.email=jwt.email
req.roles=jwt.roles
next()
}catch(err){}
하였습니다.response.locals
오브젝트를 지정하여 새 속성을 저장합니다..
export function testmiddleware(req: Request, res: Response, next: NextFunction) {
res.locals.user = 1;
next();
}
// Simple Get
router.get('/', testmiddleware, async (req: Request, res: Response) => {
console.log(res.locals.user);
res.status(200).send({ message: `Success! ${res.locals.user}` });
});
이 답변에는 이미 늦은 감이 있지만, 어쨌든 제가 해결한 방법은 다음과 같습니다.
- 유형 소스가 에 포함되어 있는지 확인합니다.
tsconfig
file스레드일 수 )file(파일명: 새로운 스레드일 수 있음) - 유형 디렉토리 내에 새 디렉토리를 추가하고 확장하거나 유형을 생성할 패키지로 이름을 지정합니다. 「Directory」를 「」로 합니다.
express
- <고객명>
express
a it it 、 「 」라고 합니다.index.d.ts
(정확히 이와 같아야 합니다.) - 마지막으로 다음과 같은 코드를 입력하면 유형을 확장할 수 있습니다.
declare module 'express' {
export interface Request {
property?: string;
}
}
노드 12.19.0 및 express 4를 사용하는 Mac에서는 인증에 Passport를 사용하여 Session 개체를 확장해야 했습니다.
위와 비슷하지만 약간 다릅니다.
import { Request } from "express";
declare global {
namespace Express {
export interface Session {
passport: any;
participantIds: any;
uniqueId: string;
}
export interface Request {
session: Session;
}
}
}
export interface Context {
req: Request;
user?: any;
}```
이 방법은 효과가 있었습니다.
declare namespace e {
export interface Request extends express.Request {
user:IUserReference,
[name:string]:any;
}
export interface Response extends express.Response {
[name:string]:any;
}
}
export type AsyncRequestHandler = (req:e.Request, res:e.Response, logger?:Logger) => Promise<any>|Promise<void>|void;
export type AsyncHandlerWrapper = (req:e.Request, res:e.Response) => Promise<void>;
또, 이러한 시그니처를 가지는 함수를 export 하는 것과 같은 코드로 사용하고 있습니다.
app.post('some/api/route', asyncHandlers(async (req, res) => {
return await serviceObject.someMethod(req.user, {
param1: req.body.param1,
paramN: req.body.paramN,
///....
});
}));
경우라면, 저는 단한, 경 the를 합니다.headers
외부 미들웨어에 속하고 나중에 내부 미들웨어에 속합니다.
// outer middleware
req.headers["custom_id"] = "abcxyz123";
// inner middleware
req.get("custom_id");
결점:
- 할 수 것은 「」입니다.
string
타입을json
★★★★★★★★★★★★★★★★★」number
을 사용하다 headers
속성이 문서화되지 않았습니다.Express는 메서드만 문서화합니다.따라서 Property에서 동작하는 Express의 정확한 버전을 사용해야 합니다.headers
.
ApiResponse 응답 ApiResponse(ApiResponse)를 Response<ApiResponse>
export interface ApiResponse {
status?: string
error?: string
errorMsg?: string
errorSubject?: string
response?: any
}
const User = async (req: Request, res: Response<ApiResponse>, next: NextFunction) => {
try {
if (!username) return res.status(400).send({ errorMsg: 'Username is empty' })
/* ... */
} catch(err){
/* ... */
}
}
.d.ts 선언은 해킹입니다.express' 미들웨어 시스템은 타자용 시스템이 아니라는 사실을 받아들이세요.그러니까 쓰지 마세요.
잘못된 코드 예시:
const auth = (req) => {
const user = // parse user from the header
if(!user)
return res.status(401).send({ result: 'unauthorized-error' })
req.user = user
return next()
}
app.get('/something', auth, (req, res) => {
// do something
})
더 나은 코드:
const auth = (req) => {
return // parse user from the header
}
app.get('/something', (req, res) => {
const user = auth(req)
if(!user)
return res.status(401).send({ result: 'unauthorized-error' })
// do something
})
사용법 등의 미들웨어를 고차적인 기능으로 되돌릴 수 있습니다.
const auth = (req) => {
return // parse user from the header
}
const withUser = (callback: (foo, req, res) => void) => (req, res) => {
const user = auth(req)
if(!user)
return res.status(401).send({ result: 'unauthorized-error' })
return callback(user, req, res)
}
app.get('/something', withUser((user, req, res) => {
// do something
}))
필요에 따라서, 그것들을 쌓을 수도 있습니다.
const withFoo = (callback) => (req, res) => { /* ... */ }
const withBar = (callback) => (req, res) => { /* ... */ }
const withBaz = (callback) => (req, res) => { /* ... */ }
const withFooBarAndBaz = (callback) => (req,res) => {
withFoo((foo) =>
withBar((bar) =>
withBaz((baz) =>
callback({ foo, bar, baz }, req, res)
)(req,res)
)(req,res)
)(req,res)
}
app.get('/something', withFooBarAndBaz(({ foo, bar, baz }, req, res) => {
// do something with foo, bar and baz
}))
안전하지 않은 돌연변이가 촉진되는 대신 언어를 사용하세요.
편집: 처음 제안한 솔루션을 사용합니다.단, 인증 함수가 에러를 발생시키는 차이점에서는 올바른 응답을 검출하여 반환할 수 있기 때문에 컨트롤러에서 실행할 필요가 없습니다.예를 들어 다음과 같습니다.
app.get('/something', withResponse((req) => {
const user = auth(req)
return success({
message: `Hi ${user.name}`
})
}))
res.send를 수동으로 호출하지 않고 반품 타입도 보냅니다.응답도 입력할 수 있습니다.tRPC도 확인해 보시기 바랍니다.
req.params 객체에 속성을 추가합니다.
req.params.foo = "bar"
언급URL : https://stackoverflow.com/questions/37377731/extend-express-request-object-using-typescript
'programing' 카테고리의 다른 글
Oracle 값 목록에서 선택하는 방법 (0) | 2023.03.17 |
---|---|
JSON.stringify가 삭제하지 않은 미정의 보존 (0) | 2023.03.17 |
왜 사람들은 리액트/JSX에 { " }을(를) 넣을까요? (0) | 2023.03.17 |
Jest transform Ignore Patterns가 작동하지 않습니다. (0) | 2023.03.17 |
ReactJs 글로벌 도우미 기능 (0) | 2023.03.17 |