어떤 타입일지 아직 모른다는 의미를 가지고 있다.
모든 타입의 값을 가질 수 있지만, 타입이 결정되지 않아서 특정 작업을 수행하려면 타입 체크가 필요
any와 비슷하지만, 더 안전하게 사용된다. unknown 타입은 직접 사용할 수 없고, 타입을 좁히거나 캐스팅해야만 조작 가능.
let value: unknown;
value = "hello"; // OK
value = 42; // OK
// 에러: 'unknown' 타입에서는 직접 작업을 할 수 없음
// console.log(value.toUpperCase());
// 타입 좁히기 후 사용
if (typeof value === "string") {
console.log(value.toUpperCase()); // OK
}
절대로 발생하지 않는 값"이라는 의미이다.
어떤 값도 가질 수 없는 타입. 주로 절대 도달할 수 없는 코드나 에러 처리를 나타낼 때 사용됨.
함수가 항상 예외를 던지거나 무한 루프에 들어가는 경우 반환 타입으로 never를 사용.
function error(message: string): never {
throw new Error(message); // 항상 예외를 던지므로 반환되지 않음
}
function infiniteLoop(): never {
while (true) {
// 무한 루프
}
}
// 타입 체킹에서 사용
type SomeType = "a" | "b";
function checkValue(value: SomeType): string {
if (value === "a") {
return "A";
} else if (value === "b") {
return "B";
} else {
const unreachable: never = value; // 이 코드는 절대 실행되지 않아야 함
return unreachable; // 타입 오류 방지
}
}
조건부 타입에서 타입을 추론하기 위해 사용되는 키워드
어떤 type context내에서 type을 변수처럼 사용한다고 생각하면 쉽다.
조건의 true분기에서 사용한다.
여러가지 활용방법들이 존재한다..
// 배열에서 요소 유형 추출
type ElementType<T> = T extends Array<infer U> ? U : T;
type A = ElementType<number[]>; // A is number
type B = ElementType<string[]>; // B is string
type C = ElementType<boolean>; // C is boolean (fallback case)
// 함수의 반환 유형 추출
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
type Fn = () => string;
type Result = ReturnType<Fn>; // Result is string
// 첫번째 인수 유형 추출
type FirstArgument<T> = T extends (arg: infer U, ...args: any[]) => any ? U : never;
type Fn = (x: number, y: string) => void;
type Arg = FirstArgument<Fn>; // Arg is number
export type TRemoveArray<T> = T extends Array<infer U> ? TRemoveArray<U> : T;
type TPromise = Promise<1>;
type ExtractPromise = Awaited<TPromise>; // 1
다음과 같은 예시코드와 requestApi가 있다고 하자.
여기서 response는 객체배열 형태이다. 객체로 왔을때도 가능하다.
const payload = {
item : '1',
} as const
const arrayResponse = [{
test : '1'
}] as const;
type TPayload = typeof payload;
type TArrayResponse = typeof arrayResponse;
const requestApi = (payload? : TPayload, signal?: AbortSignal | undefined) => Promise.resolve(arrayResponse);
여기서 첫번째 payload를 추출하는 utility type을 infer와 함깨 작성하면 다음과 같다.
화살표함수에 argument객체는 그냥 사용할 수 없다. => ...rest파라미터 형태로 spread해서 사용해야한다.
이렇게되면 args는 파라미터를 담은 배열이 되는데, 이를 destructing 해서 => 첫번째 값을 infer를 통해 type을 추론하도록 만들어주는 형식이다.
T는 제너릭으로 일단 함수형태만 올수 있도록 제약을 걸었다.
type ExtractPayload<T extends ((...args: any) => any)> = T extends ((...args: [infer Payload, ...any]) => any) ? Payload : never;
type TExtractedPayload = ExtractPayload<typeof requestApi>;
Return Type을 반환하는 Utility type을 작성하면 다음과 같다.
requestApi가 Promise를 반환하므로 => Awaited Type을 통해 래핑된 Promise를 제거해줘야한다.
배열은 number indexSignature를 가진다. => 이를 통해 배열의 내부 타입만 추출 가능하다.
type ExtractResponse<T extends ((...args: any) => any)> = Awaited<ReturnType<T>>;
type TExtractedResponse = ExtractResponse<typeof requestApi>[number];