동적 데이터를 처리해야 하는 상황
npm jwt 라이브러리와 typescript를 함께 사용할 때 어느 시점에서 유형으로 무엇을 해야할지 생각해야 합니다.
jwt는 내가 원하는 키:밸류 를 이용하여 서명을하고 검증을 할 수 있다.
token = jwt.sign({id: "1234"}, secret)
을 통해 얻은 token을 쿠키에 담아 클라이언트로 응답한다.
클라이언트는 서버에 요청할 때마다 쿠키를 같이 보내게 되고, 서버는 쿠키에서 토큰을 꺼내 검증한다.
result = jwt.verify(token, secret);
이 때, verify로 얻은 result에 id가 있는지 아닌지는 verfiy의 리턴 타입만으론 알 수 없다.
verify의 리턴은 다음과 같다.
export interface JwtPayload {
(key: string): any;
iss?: string | undefined;
sub?: string | undefined;
aud?: string | string() | undefined;
exp?: number | undefined;
nbf?: number | undefined;
iat?: number | undefined;
jti?: string | undefined;
}
위의 코드를 보면 jwt가 JwtPayload 유형으로 서명된 상태에서 주입된 ID를 가져올 방법이 없습니다. 이걸 해결하려면 어떻게 해야 할까요…
방법 1 유형 어설션(캐스팅)
1. 타입 단언(타입 캐스팅)
interface IPayload extends JwtPayload {
email: string;
}
result = jwt.verify(token, secret) as IPayload;
// 이후엔 result.email로 접근하여 사용할 수 있다.
// 하지만, 타입 캐스팅이기에 result에 정말 email 프로퍼티가 있는지는 모른다
// 다음 예제 코드를 보면, result.email이 없는게 확실하지만, 타입 단언은 이를 무시한다.
interface A {
id: string;
}
interface B extends A {
email: string;
}
function GetA(): A {
return {id: "MyId"};
}
const result = GetA() as B;
console.log(result.email); // undefined
연산자의 방법 2
in 연산자는 주어진 키가 개체에 있는지 여부를 테스트하는 연산자입니다. 유형 제약 조건은 in 연산자와 잘 작동합니다.
interface A {
id: string;
}
interface B extends A {
email: string;
}
function GetA(): A {
return {id: "MyId"};
}
const result = GetA();
if('email' in result) {
console.log(result.email);
}
방법 3 유형 술어
interface IPayload extends Payload {
id: string;
}
function hasId(obj: any): obj is IPayload {
return (obj.id !== undefined);
}
const decoded = jwt.verify(token, process.env.JWT_SECRET!);
if(hasId(decoded)){
// 타입이 좁혀져서 decoded.id 와같이 접근 가능하다
decoded.id = ...
}
방법 4 어설션 서명
이것은 TypeScript 3.7에 도입된 새로운 기능이며 다음과 같이 사용할 수 있습니다.
function assert(condition: any, msg?: string): asserts condition {
if (!condition) {
throw new AssertionError(msg);
}
}
function yell(str) {
assert(typeof str === "string");
// assert 이후로 str은 string으로 확실하게 좁혀진다
//아래 함수는 철자가 잘못되었으므로 타입스크립트 컴파일러가 에러를 잡아준다.
return str.toUppercase();
}
졸업 증서
방법이 너무 많습니다. 이 모든 방법을 외우고 암기하는 것은 좋은 방향이 아닌 것 같습니다. 중요한 것은 원칙을 이해하고 적용하는 것입니다. 유형을 한정할 수 있는 구문(유형 보호)을 발견하면 TypeScript 컴파일러가 이를 분석한 다음 코드에서 유형의 범위를 좁힙니다(유형 내향).