TypeScript type system

Junghyun Park·2021년 4월 13일
0
post-custom-banner

TypeScript란?

  • TypeScript는 JS의 static type checker(코드 실행 없이, error를 detect)임
  • TypeScript는 Typed Superset of JS (JS 코드를 그대로 오류 없이 실행 가능)
  • 실무에서 많은 경우의 오류 원인에 해당하는 type(일종의 올바른 틀, 규격)을 미리 정의해 둠으로써, 이로 인한 오류 발생 가능성과 디버깅 수고를 줄일 수 있음

TypeScript 기본 이론

https://www.typescriptlang.org/docs/handbook/intro.html
https://medium.com/jspoint/typescript-type-system-81fdb84bba75

1. Explicit Type Annotation ** : 변수나 인자의 type을 직접 정의/ 컴파일 통해 js로 변환되면 모두 사라짐

function greet(person: string, date: Date) {
  console.log(`Hello ${person}, today is ${date.toDateString()}!`);
}
greet("Maddison", Date());
//Argument of type 'string' is not assignable to parameter of type 'Date'.

2. Infer Types** : 자동으로 type을 인식도 가능/ type system이 추론하는 Type이 동일하다면 굳이 annotation 하지 X

let msg = "hello there!";
//  ^ = let msg: string

3. TypeScript는 JS의 typeof로 확인할 수 있는, string, number, boolean 등을 동일하게 포함하며, 특별한 type인 any를 더 포함함 (type을 규정하지 않고, type system도 추론할 수 없을때는 defalut로 any를 할당

4. Union Type

: 여러 타입의 종류 중 하나로 표현할 경우 사용

function printId(id: number | string) {
  console.log("Your ID is: " + id);
}
// OK
printId(101);
// OK
printId("202");
// Error
printId({ myID: 22342 });
/// => Argument of type '{ myID: number; }' is not assignable to parameter of type 'string | number'.
  Type '{ myID: number; }' is not assignable to type 'number'.
function printId(id: number | string) {
  console.log(id.toUpperCase());
// => Property 'toUpperCase' does not exist on type 'string | number'.
  Property 'toUpperCase' does not exist on type 'number'.
}
//위 처럼 하면 안됨(toUpperCase()가 number일 경우는 에러가 뜨므로)
// 아래 처럼 수정하면 OK
function printId(id: number | string) {
  if (typeof id === "string") {
    // In this branch, id is of type 'string'
    console.log(id.toUpperCase());
  } else {
    // Here, id is of type 'number'
    console.log(id);
  }
}

5. Type Aliases

: 타입을 체크해야하는 변수가 여러번 반복되는 경우, 직접 정의하는 type annotation 보다 더 큰 묶음 변수에 할당하여 활용

type Point = {
  x: number;
  y: number;
};
// Exactly the same as the earlier example
function printCoord(pt: Point) {
  console.log("The coordinate's x value is " + pt.x);
  console.log("The coordinate's y value is " + pt.y);
}
printCoord({ x: 100, y: 100 });

6. Interfaces

: Type Alias와 유사
: 유일한 차이점은 type alias는 새로운 property 추가하기 위한 re-open 불가하지만, Interface는 확장가능(..extends.. 통한 new property 추가 가능)

interface Point {
  x: number;
  y: number;
}
function printCoord(pt: Point) {
  console.log("The coordinate's x value is " + pt.x);
  console.log("The coordinate's y value is " + pt.y);
}
printCoord({ x: 100, y: 100 });

7. Type Assertions

: value의 type에 대한 정보를 더 정확히 정의하고 싶을 때 활용
: 원래 ts 컴파일러가 인식하는 타입과 다른 값으로 지정하고자 할 때 활용 (only compile time, not runtime)
: 예를들어, 아래의 경우, TS는 단지 어떤 HTMLElement를 반환하는 정보를 가지고 있으므로, 구체적으로 사용하고자 하는 Element 종류를 정의할 수 있음

const myCanvas = document.getElementById("main_canvas") as HTMLCanvasElement;

or

// .tsx 파일에 코드가 있는 경우는 제외
const myCanvas = <HTMLCanvasElement>document.getElementById("main_canvas");

8. Literal Types

: 일반적인 type들 이외에, 구체적인 값으로 type을 정의 가능
: let이 아니라 const로 변수를 정의해야 타입이 아닌 구체적 값으로 인식가능

function printText(s: string, alignment: "left" | "right" | "center") {
  // ...
}
printText("Hello, world", "left");
printText("G'day, mate", "centre");
//=>Argument of type '"centre"' is not assignable to parameter of type '"left" | "right" | "center"'.
function compare(a: string, b: string): -1 | 0 | 1 {
  return a === b ? 0 : a > b ? 1 : -1;
}

React & TypeScript

Function Component에서 props와 return 값에 대한 type 지정

// Declaring type of props - see "Typing Component Props" for more examples
type AppProps = {
  message: string;
}; /* use `interface` if exporting so that consumers can extend */
// Easiest way to declare a Function Component; return type is inferred.
const App = ({ message }: AppProps) => <div>{message}</div>;
// you can choose annotate the return type so an error is raised if you accidentally return some other type
const App = ({ message }: AppProps): JSX.Element => <div>{message}</div>;
// you can also inline the type declaration; eliminates naming the prop types, but looks repetitive
const App = ({ message }: { message: string }) => <div>{message}</div>;

useState에서는 대부분 type inference가 잘 작동

const [val, toggle] = React.useState(false);
// `val` is inferred to be a boolean
// `toggle` only takes booleans

그러나, 초기값이 설정되어 있지 않아 inferencer가 어려운 경우, 명확히 type을 지정해줘야 함

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

useEffect에서 사용하기 위해서는 리턴값이 function이거나 undefined 이도록 확인할 것

아래의 경우, setTimeout 함수 전체가 '{}'로 싸여있어야 return type을 number가 아니도록 infer가능

function DelayedEffect(props: { timerMs: number }) {
  const { timerMs } = props;
  useEffect(() => {
    setTimeout(() => {
      /* do stuff */
    }, timerMs);
  }, [timerMs]);
  // better; use the void keyword to make sure you return undefined
  return null;
}

React.FC 사용을 지양해야 하는 이유

  1. children props를 명시하지 않아도 자동으로 가짐 => 필요한 경우에만 명시하는게 명확함
  2. generic support X
  3. defaultProps와 작동 X
    참고링크
  • 대신 React.VoidFunctionComponent or React.VFC 를 사용하기 (18.0.0 버전 나오기 전까지 임시)

RN과 TS

https://dev.to/kadikraman/10-tips-for-structuring-a-react-native-project-k19
https://velog.io/@velopert/create-typescript-react-component

React Native with Typescript 설치

1. TypeScript template을 통한 설치

  • npx react-native init MyApp --template react-native-template-typescript
  • 설치완료화면

2. IOS에서 구동시켜보기

  • npx react-native run-ios


Generic Type이란?

https://joshua1988.github.io/ts/guide/generics.html#%EC%A0%9C%EB%84%A4%EB%A6%AD%EC%9D%98-%ED%95%9C-%EC%A4%84-%EC%A0%95%EC%9D%98%EC%99%80-%EC%98%88%EC%8B%9C

  • 변수형태로 클래스 외부에서 클래스 내부에서 사용되는 변수의 타입을 지정해주는 방식
profile
21c Carpenter
post-custom-banner

0개의 댓글