TypeScript

TypeScript

TypeScript 덕분에 JavaScript에 정적 타이핑(static typing)을 추가해서 개발자 생산성과 코드 품질을 향상시킬 수 있어요.

출처: 문서

본문

최소 설정 (Minimum configuration)

Material UI는 최소 TypeScript 4.9 버전을 요구해요. Vite.js with TypeScript 예제를 살펴보세요.

타입이 작동하려면 tsconfig.json에 적어도 다음 옵션들이 활성화되어 있는 것을 권장해요:

{
  "compilerOptions": {
    "lib": ["es6", "dom"],
    "noImplicitAny": true,
    "noImplicitThis": true,
    "strictNullChecks": true,
    "allowSyntheticDefaultImports": true
  }
}

엄격(strict) 모드 옵션은 @types/ 네임스페이스에 게시된 모든 타입 패키지에 요구되는 것과 같아요. 덜 엄격한 tsconfig.json을 사용하거나 일부 라이브러리를 빠뜨리면 오류가 발생할 수 있어요. 타입으로 최고의 경험을 얻으려면 "strict": true를 설정하는 것을 권장해요.

value와 이벤트 핸들러 다루기

사용자 입력과 관련된 많은 컴포넌트는 value prop이나 현재 value를 포함하는 이벤트 핸들러를 제공해요. 대부분의 상황에서 그 value는 React 내부에서만 처리되므로 객체나 배열 같은 어떤 타입이든 될 수 있어요.

하지만 그 타입이 컴포넌트의 children에 의존하는 상황, 예를 들어 Select나 RadioGroup에서는 컴파일 타임에 검증할 수 없어요. 이는 가장 건전한 선택이 unknown으로 타입을 지정하고, 개발자가 그 타입을 어떻게 좁힐지 결정하게 하는 것을 의미해요. React에서 event.target이 제네릭이 아닌 것과 같은 이유로 이런 경우에 제네릭 타입을 사용하는 가능성은 제공하지 않아요.

데모에는 타입 캐스팅을 사용하는 타입 변형들이 포함되어 있어요. 모든 타입이 단일 파일에 위치하고 매우 기본적이기 때문에 그것은 수용 가능한 트레이드오프예요. 같은 트레이드오프가 자신에게도 수용 가능한지는 직접 결정해야 해요. 라이브러리 타입은 기본적으로 엄격하고, opt-in을 통해 느슨해져요.

slotProps에서 data-* 속성 허용하기

기본적으로 슬롯 prop 타입은 임의의 data-* 속성을 거부해요. 런타임에 DOM으로 전달되더라도 그렇죠. 이것은 타입 표면을 타이트하게 유지하고 오타를 잡아줘요. DataAttributesOverrides 인터페이스를 보강(augment)해서 slotProps에 data-* 속성(예: data-testid 같은 테스트 로케이터)을 허용할 수 있어요:

// Accept any data-* attribute on every slot.
declare module '@mui/material/utils' {
  interface DataAttributesOverrides {
    [key: `data-${string}`]: string | number | boolean | undefined;
  }
}

그러면 data-* 속성이 어떤 컴포넌트의 slotProps에서도 타입 검사를 통과해요:

<Badge slotProps={{ badge: { 'data-testid': 'badge' } }} />

더 엄격한 계약을 원한다면, 사용하는 키만 선언해요. 그러면 각각을 나열하는 비용으로 자동 완성과 오타 검사를 얻을 수 있어요:

declare module '@mui/material/utils' {
  interface DataAttributesOverrides {
    'data-testid'?: string;
  }
}

Theme 커스터마이즈

테마 커스터마이즈 페이지로 이동했어요.

component prop과 관련된 복잡함

일부 TypeScript 제한 때문에, Material UI 컴포넌트를 기반으로 커스텀 컴포넌트를 만들 때 component prop을 사용하는 것이 문제가 될 수 있어요. 컴포넌트를 합성(composition)할 때는 다음 두 옵션 중 하나를 사용해야 할 거예요:

  1. Material UI 컴포넌트를 감싸서(wrap) 향상시키기
  2. styled() 유틸리티를 사용해 컴포넌트의 스타일을 커스터마이즈하기

첫 번째 옵션을 사용한다면, 더 자세한 내용은 composition 가이드를 참고하세요.

styled() 유틸리티를 사용한다면(@mui/material 또는 @emotion/styled에서 온 것이든), 아래와 같이 결과 컴포넌트를 캐스팅해야 해요:

import Button from '@mui/material/Button';
import { styled } from '@mui/material/styles';

const CustomButton = styled(Button)({
  // your custom styles go here
}) as typeof Button;

더 알아보기 (Learn more)