리액트 타입스크립트 CheatSheet

column clash·2021년 10월 6일
0
post-custom-banner

리액트에서 타입스크립트를 적용하던 중, 정리가 필요해서, 찾아보니
좋은 문서가 있어서, 벨로그에 옮겼습니다. 문제시 비공개 처리하겠습니다.

원본출처 https://github.com/typescript-cheatsheets/react

Function Components

// props 유형 선언 - 더 많은 예제는 "구성 요소 props 입력"을 참조하세요. 
type AppProps = {
  message: string;
}; /* 소비자가 확장할 수 있도록 내보낼 경우 '인터페이스'를 사용합니다. */ 

// 함수 구성 요소를 선언하는 가장 쉬운 방법; 반환 유형이 유추됩니다. 
const App = ({ message }: AppProps) => <div>{message}</div>;

// 실수로 다른 유형을 반환하는 경우 오류가 발생하도록 반환 유형에 주석을 추가할 수 있습니다. 
const App = ({ message }: AppProps): JSX.Element => <div>{message}</div>;

// 유형 선언을 인라인할 수도 있습니다. 소품 유형의 이름 지정을 제거하지만 반복적으로 보입니다. 
const App = ({ message }: { message: string }) => <div>{message}</div>;

Hooks

useState

형식 유추는 간단한 값에 대해 매우 잘 작동합니다.:

const [val, toggle] = React.useState(false);

그러나 많은 후크가 null-ish 기본값으로 초기화되며 유형을 제공하는 방법이 궁금할 수 있습니다. 명시적으로 유형을 선언하고 공용체 유형을 사용합니다.

const [user, setUser] = React.useState<IUser | null>(null);

// later...
setUser(newUser);

상태가 설정 직후 초기화되고 항상 다음 값을 갖는 경우 유형 어설션을 사용할 수도 있습니다.

const [user, setUser] = React.useState({} as IUser);

// later...
setUser(newUser);

이것은 {}유형 의 TypeScript 컴파일러에 일시적으로 "거짓" IUser입니다. user상태 를 설정하여 후속 조치 를 취해야 합니다. 그렇지 않으면 코드의 나머지 부분 user이 유형에 IUser따라 런타임 오류가 발생할 수 있다는 사실에 의존 할 수 있습니다.

useEffect / useLayoutEffect

useEffect와 useLayoutEffect는 모두 side effect을 수행하고 선택적 정리 함수를 반환하는 데 사용됩니다.

이 함수는 반환 값을 처리하지 않으며 유형이 필요하지 않습니다.
useEffect를 사용할 때는 함수나 정의되지 않은 것 외에 다른 것을 반환하지 않도록 주의하십시오.

그렇지 않으면 TypeScript와 React 둘 다 에러가 날 것입니다.
화살표 기능을 사용할 경우 다음과 같은 문제가 발생할 수 있습니다.

function DelayedEffect(props: { timerMs: number }) {
const { timerMs } = props;

useEffect(
  () =>
    setTimeout(() => {
      /* do stuff */
    }, timerMs),
  [timerMs]
);
// 나쁜 예! setTimeout은 암시적으로 숫자를 반환합니다. 
// 화살표 함수 본문이 중괄호로  묶이지 않았기 때문에
return null;
}

위의 예에 대한 해결책

function DelayedEffect(props: { timerMs: number }) {
const { timerMs } = props;

useEffect(() => {
  setTimeout(() => {
    /* do stuff */
  }, timerMs);
}, [timerMs]);
// 더 나은; void 키워드를 사용하여 정의되지 않은 
return null;
}

useRef

function Foo() {
// - 가능하면 가능한 한 구체적인 것을 선호합니다. 예를 들어 HTMLDivElement 
//는 HTMLElement보다 낫고 Element보다 훨씬 낫습니다. 
// - 기술적으로 이것은 RefObject<HTMLDivElement>를 반환합니다. 

const divRef = useRef<HTMLDivElement>(null);

useEffect(() => {
  // ref.current는 null일 수 있습니다. 이는 
  // 조건부로 ref-ed 요소를 렌더링하거나 
  if (!divRef.current) throw Error("divRef is not assigned");

  / // 이제 divRef.current는 HTMLDivElement 
  doSomethingWith(divRef.current);
});

// React가 관리할 수 있도록 요소에 대한 참조를 제공합니다. 
return <div ref={divRef}>etc</div>;
}
function Foo() {
// 기술적으로 이것은 MutableRefObject를 반환합니다.<숫자 | null> 
const intervalRef = useRef<number | null>(null);

 // 참조를 직접 관리합니다(그래서 MutableRefObject라고 합니다!) 
useEffect(() => {
  intervalRef.current = setInterval(...);
  return () => clearInterval(intervalRef.current);
}, []);


return <button onClick={/* clearInterval the ref */}>Cancel timer</button>;
}

Custom Hooks

export function useLoading() {
const [isLoading, setState] = React.useState(false);
const load = (aPromise: Promise<any>) => {
  setState(true);
  return aPromise.finally(() => setState(false));
};
return [isLoading, load] as const;
// (boolean | typeof load)[] 대신 [boolean, typeof load]를 추론 }    
}

React+TypeScript 앱에서 사용할 가능성이 있는 TypeScript 유형 목록:

type AppProps = {
message: string;
count: number;
disabled: boolean;

/** 유형의 배열! */ 
names: string[];

/** 정확한 문자열 값을 지정하는 문자열 리터럴, 함께 결합하는 공용체 유형 사용 */ 
status: "waiting" | "success";

/** 속성을 사용하지 않는 한 모든 객체(일반적이지는 않지만 자리 표시자로 유용함) */ 
obj: object;

obj2: {}; // `object`와 거의 동일, `Object`와 정확히 동일 /** 속성의 수에 제한이 없는 객체 (PREFERRED) */ 

obj3: {
  id: string;
  title: string;
};

/** 객체 배열! (공통) */ 
objArr: {
  id: string;
  title: string;
}[];

 /** 같은 유형의 속성을 가진 dict 객체 */ 
dict1: {
  [key: string]: MyTypeHere;
};

dict2: Record<string, MyTypeHere>;// dict1과 동일 

/** 호출하지 않는 한 모든 함수(권장하지 않음) */ 
onSomething: Function;

 /** 아무것도 받지 않거나 반환하지 않는 함수 (매우 일반적임) */ 
onClick: () => void;

 /** 이름이 지정된 prop이 있는 함수(매우 일반적) */ 
onChange: (id: number) => void;

/** 이벤트를 받는 대체 함수 유형 구문(매우 일반적임 ) */ 
onClick(event: React.MouseEvent<HTMLButtonElement>): void;

/** 선택적 소품(매우 일반적입니다!) */ 
optional?: OptionalType;
};

유용한 React Prop 유형 예제

export declare interface AppProps {
children1: JSX.Element; / 나쁜, 배열을 고려하지 

children2: JSX.Element | JSX.Element[]; // meh, 문자열을 허용하지 않습니다 

children3: React.ReactChildren; // 이름에도 불구하고 전혀 적절한 유형이 아닙니다. 
그것은 유틸리티 

children4: React.ReactChild[]; // 더 나은, 배열 자식을 받아들입니다.

children: React.ReactNode; // 최상, 모든 것을 수용합니다(아래의 경우 참조) 

functionChildren: (name: string) => React.ReactNode; // 자식 render prop type 

style?: React.CSSProperties;  // 스타일 소품을 전달하기 위해 

onChange?: React.FormEventHandler<HTMLInputElement>; // 이벤트를 형성합니다! 일반 매개변수는 event.target의 유형입니다.

  // 추가 정보: https://react-typescript-cheatsheet.netlify.app/docs/advanced/patterns_by_usecase/#wrappingmirroring 


props: Props & React.ComponentPropsWithoutRef<"button">; 
// 버튼 요소의 모든 props를 가장하고 ref 

props2: Props & React.ComponentPropsWithRef<MyButtonWithForwardRef>; 
// MyButtonForwardedRef의 모든 소품을 가장하고 해당 ref를 명시적으로 전달하기 위해 
}

작은 React.ReactNode 엣지 케이스
이 코드는 유형을 검사하지만 런타임 오류가 있습니다.

type Props = {
children: React.ReactNode;
};

function Comp({ children }: Props) {
return <div>{children}</div>;
}

function App() {
return <Comp>{{}}</Comp>;  // 런타임 오류: 객체가 React Child로 유효하지 않습니다! Child!
}

이는 ReactNode에 너무 넓은 {} 유형을 허용하는 ReactFragment가 포함되어 있기 때문입니다. 이를 수정하면 많은 라이브러리가 깨질 수 있으므로 현재로서는 ReactNode가 완전히 방탄이 되는 것은 아니라는 점을 유념해야 합니다.

JSX.Element 대 React.ReactNode?

좀 더 기술적인 설명은 유효한 React 노드가 React.createElement에서 반환되는 노드와 동일하지 않다는 것입니다. 구성 요소의 렌더링 결과에 관계없이 React.createElement는 항상 JSX라는 개체를 반환합니다.요소 인터페이스이지만 반응합니다.ReactNode는 구성요소의 가능한 모든 반환 값의 집합입니다.

JSX.Element -> Return value of React.createElement
React.ReactNode -> Return value of a component

유형 또는 인터페이스?

유형 또는 인터페이스를 사용하여 Props 및 State를 입력할 수 있으므로 자연스럽게 질문이 생깁니다. 어떤 것을 사용합니까?

Type- orta가 필요할 때까지 Interface를 사용하십시오 .

더 자세한 칼럼을 읽고 싶다면
https://medium.com/@martin_hotell/interface-vs-type-alias-in-typescript-2-7-2a8f1777af4c

다음은 유용한 경험 법칙입니다.

interface라이브러리 또는 타사 앰비언트 유형 정의를 작성할 때 항상 공용 API의 정의에 사용 합니다. 이렇게 하면 일부 정의가 누락된 경우 소비자가 선언 병합을 통해 이를 확장할 수 있습니다 .

type일관성과 더 제한적이기 때문에 React Component Props 및 State에 사용 하는 것을 고려 하십시오.

Forms and Events

성능이 문제가 아닌 경우(일반적으로 그렇지 않습니다!) 처리기를 인라인하는 것이 가장 쉽습니다. 유형 추론 및 컨텍스트 입력을 사용할 수 있기 때문입니다 .

const el = (
<button
  onClick={(event) => {
    /* event will be correctly typed automatically! */
  }}
/>
);
  
그러나 이벤트 핸들러를 별도로 정의해야 하는 경우 @type 정의가 
풍부한 입력과 함께 제공되므로 IDE 도구가 여기에서 매우 유용합니다. 
찾고 있는 것을 입력하면 일반적으로 자동 완성이 도움이 될 것입니다. 
다음은 onChange양식 이벤트의 경우입니다.
type State = {
  text: string;
};
class App extends React.Component<Props, State> {
  state = {
    text: "",
  };

  // typing on RIGHT hand side of =
  onChange = (e: React.FormEvent<HTMLInputElement>): void => {
    this.setState({ text: e.currentTarget.value });
  };
  render() {
    return (
      <div>
        <input type="text" value={this.state.text} onChange={this.onChange} />
      </div>
    );
  }
}
React.FormEvent<> 와 void 대신에  이벤트 핸들러 자체에 형식을 적용할 수도 있습니다.

 onChange: React.ChangeEventHandler<HTMLInputElement> = (e) => {
this.setState({text: e.currentTarget.value})

}

같은 일을 두 가지 방법으로 수행하는 이유는 무엇입니까?

첫 번째 방법은 유추된 메서드 서명 (e: React.FormEvent<HTMLInputElement>): void을 사용하고 
두번째 방법은 @types/react 에서 제공하는 것을 더 장인이 직접 손으로
만든 거라 할 수 있습니다. 둘다 유용하므로 둘다 알아두면 좋습니다.

양식에 제어되지 않는 구성 요소가 있는 onSubmit 입력

이벤트 유형에 신경 쓰지 않는다면 React.SyntheticEvent를 사용할 수 있습니다. 
대상 양식에 액세스하려는 사용자 지정 명명된 입력이 있는 경우 유형 어설션을 사용할 수 있습니다.
<f orm
  ref={formRef}
  onSubmit={(e: React.SyntheticEvent) => {
    e.preventDefault();
    const target = e.target as typeof e.target & {
      email: { value: string };
      password: { value: string };
    };
    const email = target.email.value; // typechecks!
    const password = target.password.value; // typechecks!
    // etc...
  }}
>
  <div>
    <label>
      Email:
      <input type="email" name="email" />
    </label>
  </div>
  <div>
    <l abel>
      Password:
      <input type="password" name="password" />
    </label>
  </div>
  <div>
    <input type="submit" value="Log in" />
  </div>
    </f orm>

물론 중요한 형태를 만들고 있다면 TypeScript 로 작성된 Formik 이나 React Hook Form 을 사용해야 합니다.

이벤트 유형 목록

AnimationEvent	CSS Animations.
ChangeEvent	
<input>, <select><textarea> 의 값을 변겨합니다.

ClipboardEvent	Using copy, paste and cut events.

CompositionEvent	
사용자가 간접적으로 텍스트를 입력하여 발생하는 이벤트
(예: 브라우저 및 PC 설정에 따라 미국 키보드에서 일본어를 
입력하려는 경우 추가 문자와 함께 팝업 창이 나타날 수 있음)

DragEvent	
FocusEvent

FormEvent
폼 또는 폼 요소가 포커스를 얻거나 잃을 때, 
폼 요소 값이 변경되거나 폼이 제출될 때마다 발생하는 이벤트입니다.

InvalidEvent
입력의 유효성 제한이 실패할 때 발생합니다
(예: <input type="number" max="10">누군가가 숫자 20을 삽입할 경우).

마우스, 터치 및 포인터 이벤트에 대한 기본 이벤트입니다.

MouseEvent
사용자가 포인팅 장치(예: 마우스)와 상호 작용하여 발생하는 이벤트

PointerEvent
사용자가 마우스, 펜/스타일러스, 터치스크린과 같은 
다양한 포인팅 장치를 사용하여 발생하는 이벤트로 멀티 터치도 지원합니다. 

이전 브라우저(IE10 또는 Safari 12)용으로 개발하지 않는 한 
포인터 이벤트를 사용하는 것이 좋습니다. UIEvent를 확장합니다.

TouchEvent
사용자가 터치 장치와 상호 작용하여 발생하는 이벤트입니다. UIEvent를 확장합니다.

TransitionEvent	
CSS 전환. 브라우저가 완전히 지원되지 않습니다. UIEvent 확장

UIEvent 
마우스, 터치 및 포인터 이벤트에 대한 기본 이벤트입니다.

WheelEvent
마우스 휠 또는 이와 유사한 입력 장치에서 스크롤. 
(참고: wheel이벤트와 scroll이벤트를 혼동해서는 안 됩니다. )

SyntheticEvent
위의 모든 이벤트에 대한 기본 이벤트입니다. 
이벤트 유형이 확실하지 않을 때 사용해야 합니다.

forwardRef/createRef

createRef:

class CssThemeProvider extends React.PureComponent<Props> {
 private rootRef = React.createRef<HTMLDivElement>(); // like this
 render() {
   return <div ref={this.rootRef}>{this.props.children}</div>;
 }
}

forwardRef:

type Props = { children: React.ReactNode; type: "submit" | "button" };
export type Ref = HTMLButtonElement;
export const FancyButton = React.f orwardRef<Ref, Props>((props, ref) => (
<b utton ref={r ef} className="MyClassName" type={props.type}>
{props.children}
</b utton>
));

Troubleshooting Handbook: Types

유니온을 활용한 문제해결

```

lass App extends React.Component<
{},
{
count: number | null; // 이와 같이
}
{
state = {
count: null,
};
render() {
return <div onClick={() => this.increment(1)}>{this.state.count};
}
increment = (amt: number) => {
this.setState((state) => ({
count: (state.count || 0) + amt,
}));
};
}

    

interface Admin {
role: string;
}
interface User {
email: string;
}

// 방법 1: in 키워드 사용
function redirect(user: Admin | User) {
if ("role" in user) {
// use the in operator for typeguards since TS 2.7+
routeToAdminPage(user.role);
} else {
routeToHomePage(user.email);
}
}

// 방법 2: 사용자 정의 유형 가드, 이전 TS 버전 또는 in이 충분하지 않은 경우 동일한 작업을 수행합니다.

function isAdmin(user: Admin | User): user is Admin {
return (user as any).role !== undefined;
}

    
    방법 2는 사용자 정의 유형 보호(User-Defined Type Guard) 라고도 하며
    가독성 있는 코드에 매우 유용할 수 있습니다.     
    이것이 TS 자체가 typeof및 로 유형을 구체화하는 방법 instanceof입니다.

대신 if...else체인이나 switch명령문 이 필요한 경우 "그냥 작동"해야 하지만 
    도움이 필요한 경우 Discriminated Unions를 찾으십시오 .     
    (참조: Basarat의 기록 ). 
    이것은 useReducer또는 Redux에 대한 감속기를 입력할 때 편리합니다 .
    
    ```
사용자 정의 유형 가드
일단 체크를 하고 나면 pet각 브랜치 내에서 의 타입을 알 수 있다면 훨씬 좋을 것 입니다.

너무 타이프 라이터가이라는 것을 가지고 발생 유형 가드 . 유형 보호는 일부 범위에서 유형을 보장하는 런타임 검사를 수행하는 일부 표현식입니다.

유형 술어 사용
유형 보호를 정의하려면 반환 유형이 유형 술어 인 함수를 정의하기만 하면 됩니다 .

function isFish(pet: Fish | Bird): pet is Fish {
  return (pet as Fish).swim !== undefined;
}
pet is Fish이 예제에서 우리의 유형 술어입니다. 술어는 형식을 취합니다 parameterName is Type. 여기서 parameterName은 현재 함수 서명의 매개변수 이름이어야 합니다.

isFish어떤 변수와 함께 호출 될 때마다 TypeScript는 원래 유형이 호환되는 경우 해당 변수를 특정 유형으로 좁힙니다 .

// Both calls to 'swim' and 'fly' are now okay.
let pet = getSmallPet();
 
if (isFish(pet)) {
  pet.swim();
} else {
  pet.fly();
}
타이프 라이터가 알고 할뿐만주의 petA는 Fish에 if지점; 
    또한 else브랜치 에는 a 가 없다는 것을 알고 Fish있으므로 a 가 있어야 합니다 Bird.

유형 가드 isFish를 사용하여 의 배열을 필터링하고 의 배열을 Fish | Bird
    얻을 수 있습니다 Fish.

const zoo: (Fish | Bird)[] = [getSmallPet(), getSmallPet(), getSmallPet()];
const underWater1: Fish[] = zoo.filter(isFish);
// or, equivalently
const underWater2: Fish[] = zoo.filter<Fish>(isFish);
const underWater3: Fish[] = zoo.filter<Fish>((pet) => isFish(pet));
Argument of type '(pet: Fish | Bird) => boolean' is not assignable to parameter of type '(value: Fish | Bird, index: number, array: (Fish | Bird)[]) => value is Fish'.
  Signature '(pet: Fish | Bird): boolean' must be a type predicate.
in
연산자 사용
in연산자는 타입 좁아 식으로 작용한다.

A에 대한 n in x표현, n문자열 리터럴 또는 문자열 리터럴 유형과 x노동 조합 유형, 
    옵션 또는 필요한 속성이 유형에 "true"로 지점 좁아이다 
    n, 및 선택적 또는 누락이 유형에 "거짓"지점 좁아 재산 n.

function move(pet: Fish | Bird) {
  if ("swim" in pet) {
    return pet.swim();
  }
  return pet.fly();
}

Optional Types

class MyComponent extends React.Component<{
  message?: string; // like this
}> {
  render() {
    const { message = "default" } = this.props;
    return <div>{message}</div>;
  }
}

Enum Types

가능한한 열거형을 사용하지 않는 것이 좋습니다 .

열거형에는 몇 가지 문서화된 문제가 있습니다 (TS 팀이 동의함 ). 열거형에 대한 더 간단한 대안은 문자열 리터럴의 공용체 유형을 선언하는 것입니다.

export declare type Position = "left" | "right" | "top" | "bottom";

열거형을 사용해야 하는 경우 TypeScript의 열거형은 기본적으로 숫자를 사용한다는 점을 기억하십시오. 일반적으로 대신 문자열로 사용하고 싶을 것입니다.

export enum ButtonSizes {
  default = "default",
  small = "small",
  large = "large",
}

// usage
export const PrimaryButton = (
  props: Props & React.HTMLProps<HTMLButtonElement>
) => <Button size={ButtonSizes.default} {...props} />;

Type Assertion

때로는 사용 중인 유형이 생각보다 좁거나 다른 API와 함께 작동하기 위해 유니온 유형을 보다 구체적인 유형으로 주장해야 하므로 as키워드를 사용하여 주장해야 한다는 것을 TypeScript보다 더 잘 알고 있는 경우가 있습니다. 이것은 컴파일러에게 당신이 자신보다 더 잘 알고 있음을 알려줍니다.

class MyComponent extends React.Component<{
  message: string;
}> {
  render() {
    const { message } = this.props;
    return (
      <Component2 message={message as SpecialMessageType}>{message}</Component2>
    );
  }
}

Advance

Union Types

Overloading Function Types

특히 함수와 관련하여 유니온 유형 대신 오버로드해야 할 수도 있습니다. 
함수 유형을 작성하는 가장 일반적인 방법은 다음과 같은 약어를 사용합니다.

type FunctionType1 = (x: string, y: number) => number;

그러나 이것은 Overloading를 허용하지 않습니다. 
implementation이 있는 경우 function 키워드를 사용하여 서로 뒤에 배치할 수 있습니다.

```

function pickCard(x: { suit: string; card: number }[]): number;
function pickCard(x: number): { suit: string; card: number };
function pickCard(x): any {
// implementation with combined signature
// ...
}

그러나 구현이 없고 .d.ts정의 파일 만 작성하는 경우에도 도움이 되지 않습니다. 
이 경우 속기를 생략하고 구식 방식으로 작성할 수 있습니다. 
여기서 기억해야 할 핵심은 TypeScript에 관한 한 다음과 
functions are just callable objects with no key
같습니다.
type pickCard = {
  (x: { suit: string; card: number }[]): number;
  (x: number): { suit: string; card: number };
  // no need for combined signature in this form
  // you can also type static properties of functions here eg `pickCard.wasCalled`
};

실제 오버로드된 함수를 구현할 때 구현에서 처리할 결합된 호출 서명을 선언해야 하며 이는 유추되지 않습니다. DOM API에서 오버로드의 예를 쉽게 볼 수 있습니다

핸드북에서 오버로딩에 대해 자세히 읽어보십시오.

유추된 유형 사용

TypeScript의 유형 유추에 의존하는 것은 훌륭합니다... 
유추된 유형이 필요하다는 것을 깨닫고 다시 돌아가서 
유형/인터페이스를 명시적으로 선언하여 재사용을 위해 내보낼 수 있을 때까지입니다.

다행히 , 를 사용 typeof하면 그렇게 할 필요가 없습니다.
아무 값이나 사용하십시오.

    const [state, setState] = React.useState({
  foo: 1,
  bar: 2,
}); // {foo: number, bar: number}로 유추된 상태 유형 

const someMethod = (obj: typeof state) => {
    
 // 유추되었지만 상태 유형 파악 
  // obj를 사용하는 일부 코드 
  setState(obj); // 작동합니다 
};

부분 유형 사용

슬라이싱 상태 및 소품 작업은 React에서 일반적입니다.
다시 말하지만, Partial제네릭 유형 을 사용하는 경우 유형을 명시적으로
재정의할 필요가 없습니다 .
const [state, setState] = React.useState({
  foo: 1,
  bar: 2,
}); // 상태 유형은 {foo: number, bar: number}로 추론됨 

// 참고: 오래된 상태 병합은 React.useState에서 실제로 권장되지 않습니다. 
/// 여기서는 Partial을 사용하는 방법을 시연하는 것뿐입니다. 
const partialStateUpdate = (obj: Partial<typeof state>) =>
  setState({ ...state, ...obj });

// later on...
partialStateUpdate({ foo: 2 }); // 이것은 작동합니다

필요한 유형이 내보내지지 않았습니다!

이것은 성가실 수 있지만 여기에 유형을 잡는 방법이 있습니다!

구성 요소의 Prop 유형 가져오기:
React.ComponentProps및 사용 typeof및 선택적으로 Omit겹치는 유형

 import { Button } from "library"; // 그러나 ButtonProps를 내보내지 않습니다! oh no!
    
type ButtonProps = React.ComponentProps<typeof Button>;  // 문제 없어요! 
    
type AlertButtonProps = Omit<ButtonProps, "onClick">; // 수정
const AlertButton: React.FC<AlertButtonProps> = (props) => (
  <Button onClick={() => alert("hello")} {...props} />
);

ComponentPropsWithoutRef(ComponentProps 대신) 및
ComponentPropsWithRef(귀하의 구성 요소가 특별히 참조를 전달하는 경우 )
사용할 수도 있습니다.

함수의 반환 유형 파악: 다음을 사용합니다 ReturnType

// 일부 라이브러리 내부 - 반환 유형 { baz: number }가 유추되었지만 내보내지지 않았습니다.
function foo ( bar : string ) {
return { baz : 1 } ;
}

// 앱 내부에서 필요한 경우 { baz: number }
type FooReturn = ReturnType < typeof foo > ; // { 바즈: 숫자 }

사실 공개된 거의 모든 것을 가져올 수 있습니다.
Ivan Koshelev의 이 블로그 게시물을 참조하세요 .

function foo() {
  return {
    a: 1,
    b: 2,
    subInstArr: [
      {
        c: 3,
        d: 4,
      },
    ],
  };
}

type InstType = ReturnType<typeof foo>;
type SubInstArr = InstType["subInstArr"];
type SubIsntType = SubInstArr[0];

let baz: SubIsntType = {
  c: 5,
  d: 6, // 유형 검사 확인! 
};

// 
한 줄로 작성할 수도 있지만 //하지만 앞으로 읽을 수 있는지 확인하십시오. 
//(점프 없이 왼쪽에서 오른쪽으로 한 번 읽는 것으로 이해할 수 있음) 
type SubIsntType2 = ReturnType<typeof foo>["subInstArr"][0];
let baz2: SubIsntType2 = {
  c: 5,
  d: 6, // 유형 검사 ok! 
};

TS는 또한 Parameters함수의 매개변수를 추출하기 위한 유틸리티 유형 과 함께 제공됩니다.
더 많은 "사용자 정의"의 경우 infer키워드는 이에 대한 기본 빌딩 블록이지만 익숙해지는 데 약간의 시간이 걸립니다. 위의 유틸리티 유형에 대한 소스 코드와 이 예제 를 보고 아이디어를 얻으십시오. Basarat 도 좋은 비디오를 가지고infer 있습니다.

필요한 유형이 존재하지 않습니다!

내보내지 않은 유형이 있는 모듈보다 더 짜증나는 것은 무엇입니까? 
유형 이 지정되지 않은 모듈 

걱정마! 이 문제를 해결할 수 있는 몇 가지 방법이 있습니다.

Slapping any on everything

더 게으른 방법은 새 형식 선언 파일을 만드는 typedec.d.ts것입니다.  아직 이 파일이 없다면 디렉토리 루트 include에 있는 tsconfig.json파일 의 배열 을 확인하여 TypeScript에서 파일 경로를 확인할 수 있는지 확인하십시오 
// inside tsconfig.json
{
  // ...
  "include": [
    "src" // automatically resolves if the path to declaration is src/typedec.d.ts
  ]
  // ...
}

이 파일 내에서 원하는 모듈에 대한 선언 구문(예: my-untypeed-module-)을
선언 파일에 추가합니다.

// inside typedec.d.ts

declare module "my-untyped-module";

오류 없이 작동하는 데 필요한 경우 이 한 줄만으로도 충분합니다. 

이 솔루션은 유형이 지정되지 않은 모듈이 몇 개 미만인 경우 해결 방법으로 잘 작동합니다.
자동유형방식이 존재합니다.

TypeScript를 --allowJs및 와 함께 사용 --declaration하여 라이브러리 유형에서 TypeScript의 "최상의 추측"을 볼 수 있습니다 .

이것이 제대로 작동하지 않으면 dts-gen개체의 런타임 모양을 사용 하여 사용 가능한 모든 속성을 정확하게 열거하는 데 사용합니다. 이것은 매우 정확한 경향이 있지만 도구는 아직 추가 유형을 채우기 위해 JSDoc 주석을 스크래핑하는 것을 지원하지 않습니다.

npm install -g dts-gen
dts-gen -m < 귀하의 모듈 >

다른 자동화된 JS에서 TS로의 변환 도구 및 마이그레이션 전략이 있습니다. 
MIGRATION 치트시트를 참조하십시오 .


    Typing Exported Hooks

Hook을 입력하는 것은 순수 함수를 입력하는 것과 같습니다.

다음 단계는 두 가지 가정 하에 작동합니다.

섹션의 앞부분에서 설명한 대로 유형 선언 파일을 이미 만들었습니다.
소스 코드, 특히 사용할 기능을 직접 내보내는 코드에 액세스할 수 있습니다. 대부분의 경우 index.js파일에 보관 됩니다. 일반적으로 후크를 완전히 정의 하려면 최소 두 가지 유형 선언(하나는 Input Prop용 이고 다른 하나는 Return Prop용 )이 필요합니다. 입력하려는 후크가 다음 구조를 따른다고 가정합니다.

    // ...
const useUntypedHook = (prop) => {
  // some processing happens here
  return {
    /* ReturnProps */
  };
};
export default useUntypedHook;

그런 다음 유형 선언은 다음 구문을 따라야 합니다.

declare module 'use-untyped-hook' {
  export interface InputProps { ... }   // type declaration for prop
  export interface ReturnProps { ... } // type declaration for return props
  export default function useUntypedHook(
    prop: InputProps
    // ...
  ): ReturnProps;
}

예를 들면 다음과 같습니다.

// inside src/index.js
const useDarkMode = (
  initialValue = false, // -> input props / config props to be exported
  {
    // -> input props / config props to be exported
    element,
    classNameDark,
    classNameLight,
    onChange,
    storageKey = "darkMode",
    storageProvider,
    global,
  } = {}
) => {
  // ...
  return {
    // -> return props to be exported
    value: state,
    enable: useCallback(() => setState(true), [setState]),
    disable: useCallback(() => setState(false), [setState]),
    toggle: useCallback(() => setState((current) => !current), [setState]),
  };
};
export default useDarkMode;
주석에서 알 수 있듯이 이러한 구성 props를 내보내고 앞서 언급한 구조에 따라 props를 반환하면 다음과 같은 유형의 내보내기가 발생합니다.
declare module "use-dark-mode" {
  /** 
   * `useDarkMode`의 특정 측면을 지정할 수 있도록 하는 구성 개체 
   */ 
  export interface DarkModeConfig {
    classNameDark?: string;  // "다크 모드"를 설정하기 위한 className. 기본값 = "다크 모드"입니다. 
    classNameLight?: string; // "Light 모드"를 설정하기 위한 className. 기본값 = "Light 모드"입니다. 
    element?: HTMLElement; // className을 적용할 요소. 기본값 = `document.body` 
    onChange?: (val?: boolean) => void; // 사용자 정의 콜백으로 기본 className 핸들러를 재정의합니다.
    storageKey?: string; // `localStorage` 키를 지정합니다. 기본값 = "다크 모드". 영구 저장소를 비활성화하려면 'null'로 설정합니다. 
    storageProvider?: WindowLocalStorage; // 스토리지 제공자. 기본값 = `localStorage`. 
    global?: Window; // 전역 객체. 기본값 = `창`. 
  }
  /** 
   * `useDarkMode` 호출에서 반환된 객체. 
   */ 
  export interface DarkMode {
    readonly value: boolean;
    enable: () => void;
    disable: () => void;
    toggle: () => void;
  }
   /** 
   * 애플리케이션의 "다크 모드" 구성 요소를 구현하는 데 도움이 되는 사용자 지정 React Hook. 
   */ 
  export default function useDarkMode(
    initialState?: boolean,
    config?: DarkModeConfig
  ): DarkMode;
}

내보낸 구성 요소 입력

타입이 지정되지 않은 클래스 컴포넌트를 타이핑하는 경우
타입을 선언한 후 타입 선언을 보유하는 class UntypedClassComponent extends React.Component<UntypedClassComponentProps, any> {}where를 사용하여 타입을 익스포트한다는 점을 제외하면 접근 방식에는 거의 차이가 없습니다 UntypedClassComponentProps.

예를 들어, React Router 6 유형에 대한 sw-yx의 Gist는 유형이 지정되지 않은 RR6을 입력하는 유사한 방법을 구현했습니다.

declare module "react-router-dom" {

import * as React from 'react';
// ...
type NavigateProps = {
to: string | number,
replace?: boolean,
state?: T
}
//...
export class Navigate<T = any> extends React.Component<NavigateProps>{}
// ...

TypeScript의 자주 알려진 문제

React 개발자가 자주 접하는 항목의 목록으로,
TS에는 이에 대한 솔루션이 없습니다. 반드시 TSX만 해당되는 것은 아닙니다.

개체 요소 null 검사 후 TypeScript가 좁혀지지 않습니다.

profile
풀스택 개발 중...
post-custom-banner

0개의 댓글