간단한 숫자야구, 반응속도체크, 가위바위보 게임을 구현해보면서 props
, setTimout/setInterval
, typeof/keyof
, 고차함수
는 어떻게 타이핑되는지 알아보자.
✅ 부모 컴포넌트에서 자식 컴포넌트로 props
를 전달하는 과정은 다음과 같다.
// 부모컴포넌트
<Try tryInfo={v} />
// 자식컴포넌트
const Try = ({tryInfo}) => {
return (...);
};
✅ props
에 타입을 지정해주려면 다음과 같이 작성할 수 있다.
const Try = ({tryInfo}: {tryInfo: TryInfo}) => {
return (...);
};
✅ 하지만, 다음과 같이 작성할 것을 추천한다.
React
에서는 generic
으로 간단하게 함수형 컴포넌트의 props
에 대한 타입을 적을 수 있다. 함수형 컴포넌트는 생략해서 사용을 해왔지만 FunctionComponent
타입으로 제네릭을 포함하고 있다. 이 제네릭 요소에 아래와 같이 props의 타입을 정의를 해주면 된다.const Try: FunctionComponent<{tryInfo: TryInfo}> = ({ tryInfo }) => {
return (...);
};
✅ 클래스형 컴포넌트에서는 React.Component
의 generic 첫번째 인자가 props
타입을 정의하는 자리이다. 만약에 state
에 대한 정의가 필요없다면, props
에 대한 타입 정의만 넣어주면 된다.
class Try extends React.Component<{ tryInfo: TryInfo }> {
render() {...}
}
✅ state
에 대한 타입정의만 필요한 경우에는 props자리에 {} 빈 객체로 표기해줘야 한다.)
class Try extends React.Component<{}, State> {
render() {... }
}
✅ 함수형 컴포넌트에서는 useState hooks
를 사용하기 때문에 state
자리는 필요가 없다.
setTimeout
을 이용해 일정 시간이 지난 후에 함수를 실행하는 방법setInterval
을 이용해 일정 시간 간격을 두고 함수를 실행하는 방법✅ 타입스크립트가 현재 본인을 실행중인 환경을 node.js
인지 browser
인지 구분 못하는 경우가 있다.
window.setTimeout()
처럼 window
를 명시적으로 사용해준다.✅ 명시적으로 window.setTimeout()
및 window.clearTimeout()
을 호출한다.
✅ 화면의 렌더링에는 영향을 주지 않는 useRef
를 사용해서 setTimeout
에 대한 정보를 변수로 저장한다.
useRef
는 값이 변경되어도 re-render
가 안되기 때문에 View
와 관련된 것이 아니라면 useRef
를 쓰고, 화면의 상태와 관련된 것이라면 useState
를 쓴다.✅ 경우에 따라 알맞은 useRef
의 타입정의를 골라서 타입정의를 한다.
useRef(null)
의 경우 내부의 useRef
의 current
가 read-only
속성이기 때문에 값을 넣을 수 없다.useRef<number|null>(null)
로 정의를 해주게 되면, React.refObject.current
에서 React.MutableRefObject<number | null>.current
로, current
가 변경가능한 mutable
한 속성이 된다.✏️ setTimeout() 사용 예시
// use ref to store the timer id
const refTimer = useRef<number | null>(null);
// trigger the timer
const startTimer = () => {
if (refTimer.current !== null) return;
refTimer.current = window.setTimeout(() => {
/* do something here */
}, 5000);
};
// stop the timer
const stopTimer = () => {
if (refTimer.current === null) return;
window.clearTimeout(refTimer.current);
refTimer.current = null;
};
✏️ setInterval() 사용 예시
const intervalref = useRef<number | null>(null);
// Start the interval
const startInterval = () => {
if (intervalref.current !== null) return;
intervalref.current = window.setInterval(() => {
/* ...*/
}, 1000);
};
// Stop the interval
const stopInterval = () => {
if (intervalref.current) {
window.clearInterval(intervalref.current);
intervalref.current = null;
}
};
💡 잠깐)
useRef
세가지 타입 정의참고하자! TypeScript React에서 useRef의 3가지 정의와 각각의 적절한 사용법
<@types/react/index.d.ts> // intialValue의 타입과 useRef의 타입을 일치시켰을때 Mutable한 RefObject가 된다. function useRef<T>(initialValue: T): MutableRefObject<T>; //MutableRefObject interface function useRef<T = undefined>(): MutableRefObject<T | undefined>; interface MutableRefObject<T> { current: T; } function useRef<T>(initialValue: T|null): RefObject<T>; // RefObject interface interface RefObject<T> { readonly current: T | null; }
✅ 두 object의 값들은 상수, 즉 변하지 않는 값이므로 as const
고정시켜주자.
rspCoords
: 가위, 바위, 보 이미지가 나타날 좌표 (coordinate)scores
: 승부 결과를 계산해줄 가위,바위,보 각각의 고유한 값✅ 가위바위보 버튼을 클릭시 computChoice
라는 함수가 호출되면서 imgCoords
를 인자로 받아온다. type
을 만들어서 이 값의 타입을 정의해보자.
const computerChoice = (imgCoords: ImgCoords) => {...}
1️⃣ 값을 넣어주는 기본적인 방법
2️⃣ typeof
를 통해 rspCoords
의 타입을 이용한다.
3️⃣ key of
를 통해 rspCoords
의 키값을 이용한다.
4️⃣ 다음과 같이 작성하여 ImgCoords
의 값 변경에도 유동적으로 변환되게 하고, 또한 타입을 명시할 수 있다.
💡중요) type of, keyof ,Mapped Type
✅ type of
: 값 공간에 있는 값에typeof
연산자를 적용하여 값 공간의 값을 타입 공간에서 타입으로 이용할 수 있다.let s = "hello"; let n: typeof s; // let n : string const add1 = (x:number)=>x+1 type MyAdd1Type = typeof add1 // (x:number)=>number // Error (<>안에는 타입이 들어가야 하기 때문이다.) function f() { return { x: 10, y: 3 }; } type P = ReturnType<f>; // 정상동작 function f() { return { x: 10, y: 3 }; } type P = ReturnType<typeof f>; type P = { x: number; y: number; }
✅ keyof
: 이미 존재하는 오브젝트를 사용한 타입 지정이 가능하다.// no index signature type Point = { x: number; y: number }; type P = keyof Point; // type P = 'x' | 'y' // with index signature type Arrayish = { [n: number]: unknown }; type A = keyof Arrayish; // type A = number // 자바스크립트 오브젝트 키는 스트링 타입으로 반드시 강제변환되기 때문에 숫자도 허용한다. type Mapish = { [k: string]: boolean }; type M = keyof Mapish; // type M = string | number
✚ 강제 형 변환
: TypeScript는 기본적으로 객체의 프로퍼티를 읽을 때, string타입의 key 사용을 허용하지 않기 때문에 as 를 통해서 강 형 변환을 해준다.const obj = { foo: "hello", } let propertyName = "foo" console.log(obj[propertyName]) // compile error!
const scores = { r : 1, s : 0, p : -1 } as const // 추론된 타입 👉 {r: 1, s: 0, p: -1} Object.keys(scores) // 추론된 타입 👉 string[] // 따라서 더 명확한 타입선언을 위해 type assertion을 해준다. Object.keys(scores) as ['r', 's', 'p'] // 추론된 타입 👉 ["r", "s", "p"] // 동적으로 assertion 하기위해 typeof 나 keyof를 사용해도 좋다.
참고 : TypeScript에서 string key로 객체에 접근하기
✅ Mapped Type
: 기존 정의된 타입을 새로운 타입으로 변환해주는 문법
- 유니온 타입의Mapped Type
type Test = 'A' | 'B' | 'C'; type MappedTest = { [K in Test]: number }; const mappedTest: MappedTest = { A: 1, B: 2, C: 3, }
- 인터페이스, 타입을 이용한 Mapped Type
type Subset<T> = { [K in keyof T]?: T[K]; } const mappedTest: Subset<MappedTest> = { A: 1, // 생략 가능 B: 2, // 생략 가능 C: 3, // 생략 가능 }
✅ 참고로 computerChoice의 타입 선언을 보면 undefined가 포함된다.
!
를 사용하여 절대로 undefined가 나오지 않는다는 강한 명시를 해준다.💡 중요) 타입스크립트에서의
!
와?
!
는 두가지로 사용✅ Null이 아닌 어선셜 연산자(Non-null assertion operator)
: Null이 아닌 어선셜 연산자는 피연산자가 null이 아니라고 컴파일러에게 전달하여 일시적으로 Null 제약조건을 완화한다.즉,
null
일 가능성이 존재한다고 추론하는 경우!
연산자를 추가하여 무조건 값이 할당되니null
을 못오게 한다.console.log(obj.lastName!.toString());
✅ 확정 할당 어선셜(Definite Assignment Assertions)
: 값이 무조건 할당되어있다고 컴파일러에게 전달하여 값이 없어도 변수 또는 객체를 사용할 수 있다.
- 변수 x의 값을 number 타입으로 설정 후 값을 할당하지 않고 사용하면 다음 경고문이 출력.
- x의 타입을 설정할 때 : 앞에
!
연산자를 사용하면 경고문이 사라집니다let x! : number; console.log(x + x); or let x : number; console.log(x! + x);
?
연산자에 대한 자세한 내용은 타입스크립트 물음표(?), 선택적 프로퍼티, 옵셔널 체이닝
✅ 일반적으로는 onClick = {onClickBtn}
을 많이 보겠지만, 다음은 인자를 가지고 있고 함수에 함수를 부르고 있는 모습이다.
⭐️ 타입스크립트에서는 함수는 변수에 담긴 함수 표현식이고, 이때 함수표현식이란 일종의 값을 의미한다. 따라서, 함수의 반환값으로 함수를 사용하는 것이 가능하다. 이처럼 어떤 함수가 또 다른 함수를 반환할 때 그 함수를 고차함수라고 한다.
const add = (a: number) => { return (b: number) => { return a + b; }; }; // 곧바로 실행 console.log(add(3)(8)); // 11 // 한 번 걸쳤다가 실행 const first = add(3); console.log(first(8)); // 11
고차함수에 대해서 더 알아보기
출처 및 참고하기 좋은 사이트