-
TypeScript로 불필요한 변수 선언 없애기: `satisfies` 활용법Javascript 2024. 8. 24. 10:34
이번 글에서는 TypeScript에서
satisfies
를 활용하여 코드 내 불필요한 변수 선언을 줄이는 방법을 소개합니다.satisfies
는 코드를 더 간결하고 효율적으로 만드는 데 유용한 기능입니다.변수 선언 없이 타입을 지정하는 방법
타입 주석을 통해 변수 선언 시 타입을 지정할 수 있지만, 이로 인해 불필요한 변수를 선언해야 하는 경우가 많습니다.
satisfies
를 사용하면 이러한 불필요한 변수를 줄일 수 있습니다. 구체적인 예시를 통해 알아보겠습니다.예시 1: 타입 포괄성 체크
switch
문에서 모든 가능한 타입을 포괄적으로 확인하는 방법으로never
타입을 활용할 수 있습니다.다음은 그 예시입니다.
type Animal = "dog" | "cat" | "pig"; const awesomeFunction = (animal: Animal) => { switch (animal) { case "cat": return "meow"; case "dog": return "bowwow"; case "pig": return "oink oink"; default: const _: never = animal; } };
이 코드는 모든
case
를 처리했기 때문에default
절에 도달했을 때animal
이never
타입이 됩니다.Animal
에 새로운 값이 추가되면 컴파일러가 이를 감지하여 알려줍니다.하지만 위 코드는 불필요한 변수를 선언하고 있습니다.
satisfies
를 이용해 이를 제거할 수 있습니다.satisfies를 사용한 개선
satisfies
를 사용하여 불필요한 변수를 제거한 코드는 다음과 같습니다.type Animal = "dog" | "cat" | "pig"; const awesomeFunction = (animal: Animal) => { switch (animal) { case "cat": return "meow"; case "dog": return "bowwow"; case "pig": return "oink oink"; default: return animal satisfies never; } };
이렇게 하면 불필요한 변수 선언 없이도 필요한 기능을 구현할 수 있습니다.
default
절은 남은animal
이 없는지를 확인하는 역할을 하므로, 변수 선언이 필요하지 않습니다.default
절에서return animal
을 하면awesomeFunction
의 타입은 다음과 같습니다.typeof awesomeFunction = (animal: Animal) => "meow" | "bowwow" | "oink oink"
만약
return animal
을 하지 않는다면 타입에undefined
가 포함됩니다. 따라서return
을 명시하는 것이 좋습니다.예시 2: 함수 인자에 적용하기
라이브러리에서 종종 "인자로 객체를 받지만, 키는 문자열이면 상관없다"는 함수를 보게 됩니다.
이럴 때도
satisfies
가 유용합니다. 예를 들어,zod
를 사용한 폼을 구현해보겠습니다.satisfies 없이 zod 스키마 선언
아래는 기본적인 폼 구현입니다.
import { zodResolver } from "@hookform/resolvers/zod"; import { useForm } from "react-hook-form"; import { z } from "zod"; const awesomeFormSchema = z.object({ name: z.string(), address: z.string(), }); type AwesomeFormSchema = z.infer<typeof awesomeFormSchema>; const AwesomeFormPage = () => { const { register } = useForm<AwesomeFormSchema>({ resolver: zodResolver(awesomeFormSchema), }); return ( <form> <label> 이름 <input {...register("name")} /> </label> <label> 주소 <input {...register("address")} /> </label> </form> ); };
여기서 "이름"과 "주소" 필드에 필수 입력과 오류 메시지를 추가해보겠습니다.
import { zodResolver } from "@hookform/resolvers/zod"; import { useForm } from "react-hook-form"; import { z } from "zod"; const awesomeFormSchema = z.object({ name: z.string().min(1, { message: "이름은 필수 항목입니다." }), address: z.string().min(1, { message: "주소는 필수 항목입니다." }), }); type AwesomeFormSchema = z.infer<typeof awesomeFormSchema>; const AwesomeFormPage = () => { const { register, formState: { errors }, } = useForm<AwesomeFormSchema>({ resolver: zodResolver(awesomeFormSchema), }); return ( <form> <label> 이름 <input {...register("name")} /> <p>{errors.name?.message}</p> </label> <label> 주소 <input {...register("address")} /> <p>{errors.address?.message}</p> </label> </form> ); };
하지만 오류 메시지와 라벨에 사용된 문구가 각각 하드코딩되어 있는 점이 아쉽습니다.
이를 통일해보겠습니다.
const awesomeFormLabel = { name: "이름", address: "주소", }; const awesomeFormSchema = z.object({ name: z.string().min(1, { message: `${awesomeFormLabel.name}은 필수 항목입니다.` }), address: z.string().min(1, { message: `${awesomeFormLabel.address}은 필수 항목입니다.` }), }); type AwesomeFormSchema = z.infer<typeof awesomeFormSchema>; const AwesomeFormPage = () => { const { register, formState: { errors }, } = useForm<AwesomeFormSchema>({ resolver: zodResolver(awesomeFormSchema), }); return ( <form> <label> {awesomeFormLabel.name} <input {...register("name")} /> <p>{errors.name?.message}</p> </label> <label> {awesomeFormLabel.address} <input {...register("address")} /> <p>{errors.address?.message}</p> </label> </form> ); };
이렇게 하면
awesomeFormLabel
과awesomeFormSchema
사이에 타입적인 연결이 없기 때문에 다른 키를 추가할 수 있습니다.이를 방지하기 위해
satisfies
를 사용해봅시다.satisfies로 개선하기
satisfies
를 사용하면 불필요한 변수를 없애고 필요한 것을 구현할 수 있습니다.import { z, type ZodSchema } from "zod"; type SchemaKey = "name" | "address"; const awesomeFormLabel = { name: "이름", address: "주소", } as const satisfies Record<SchemaKey, string>; const awesomeFormSchema = z.object({ name: z.string().min(1, { message: `${awesomeFormLabel.name}은 필수 항목입니다.` }), address: z.string().min(1, { message: `${awesomeFormLabel.address}은 필수 항목입니다.` }), } satisfies Record<SchemaKey, ZodSchema>);
이렇게 하면 불필요한 변수를 없애고
awesomeFormLabel
과awesomeFormSchema
간에 타입적 연결을 설정할 수 있습니다.satisfies
를 사용하면 변수를 선언하지 않고도 타입을 강제할 수 있습니다.이처럼
satisfies
는 코드를 간결하게 하고 타입 안전성을 높이는 데 유용합니다.요약
이번 글에서는
satisfies
를 활용하여 불필요한 변수 선언을 줄이고 타입 안전성을 높이는 방법을 알아보았습니다.다양한 상황에서
satisfies
가 유용하게 쓰일 수 있으니, 아직 사용해보지 않으셨다면 꼭 시도해보시기 바랍니다!그럼.
'Javascript' 카테고리의 다른 글
lodash-es보다 가볍고 빠른 es-toolkit으로 전환하기 (0) 2024.08.24 TypeScript의 고급 타입 시스템과 React Hooks 활용법 (0) 2024.08.24 TypeScript로 타입을 강화하는 방법: satisfies와 Uppercase<T> 활용하기 (0) 2024.08.24 NextJS 앱 자체 호스팅: 실제 사례로 알아보는 최적의 방법 (0) 2024.08.09 JavaScript 학습의 어려움과 해결 방법 (0) 2024.08.05