
간단한 숫자야구, 반응속도체크, 가위바위보 게임을 구현해보면서 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고차함수에 대해서 더 알아보기
출처 및 참고하기 좋은 사이트
Aaron had always considered himself an amateur when it came to gambling. He approached a new blackjack site with the mindset of just https://velvetspincasino1.com/ another casual player, making small bets and experimenting with different strategies. Despite his initial lack of confidence, Aaron was determined to make the most of his experience.