타입스크립트

기멜·2021년 12월 27일
0

Typescript

목록 보기
1/2

타입스크립트를 알아보자!

타입스크립트란?

타입스크립트는 자바스크립트의

tsx / ts

  • React 컴포넌트다 ? => tsx사용
  • reducer, redux등 jsx가 아닌 파일이다? => ts사용
  • React 컴포넌트인데 .ts 를 쓰면 에러가 난다.

Props

  • 부모 컴포넌트에서 자식 컴포넌트에 props 전달 시 자식이 받게 될 props interface를 정의해야 한다.
// Child.tsx
interface ChildProps {
    color: string;
    onClick: () => void;
}
export const Child = ({ color, onClick }: ChildProps) => {
    return <div onClick={onClick}>{color}</div>
}

// Parent.tsx
import { Child } from './Child';

const Parent = () => {
  return <Child color="red" onClick={() => console.log('hi')} />
};

React.FC<>를 명시함으로서 해당 함수가 리액트의 컴포넌트라는 걸 알려줄 수 있다.
React.FC<프롭타입> 제네릭에 프롭타입을 적어서 props의 타입도 정의할 수 있다.

export const ChildAsFC: React.FC<ChildProps> = ({ color }) => {
  return <div>{color}</div>
}

State

useState 사용 시 useState의 제네릭 부분에 타입을 명시할 수 있다.

단순 string, number 등은 타입스크립트가 추론할 수 있지만 array, object등은 따로 적어줄 필요가 있다

  
const Example: React.FC = () => {
    const [name, setName] = useState('');
    const [lists, setLists] = useState<string[]>([]);
    
    const handleClick = () => {
    setLists([...lists, name]);
	}
    //...
}

// const [lists, setLists] = useState([]);
// 타입을 안적으면 lists의 타입은 never[]가 되어 에러가 발생한다
  

자바스크립트는 수정할 일이 생기면 프로젝트에서는 복잡합니다.
type 관련된 버그들이 많이 발생합니다. 남이 짠 코드에 뭔가를 더하거나 수정할 때
알 수 없는 타입관련 버그들이 생길텐데 이럴 때 타입스크립트로 만들어졌길 바래야 합니다.

타입스크립트를 쓰면 에러메세지도 더 정확해집니다.
엄격한 타입룰 덕분에 "숫자가 들어와야하는데 왜 문자를 쓰니?" "object에 apend()라는 건 없어, append()말하는거 아니야?" 라던지 이렇게 친절하게 알려줍니다.

타입스크립트 간단 정리

  let 이름:string = 'kim'

변수를 만들 때 타입지정이 가능합니다.
변수명:타입명 이렇게 씁니다.
타입으로 쓸 수 있는 것들은 string, number, boolean, bigint, null, undefined,[], {} 등이 있습니다.

  let 이름:string = 'kim';
  이름 = 123;

타입을 지정해놓으면 타입이 의도치 않게 변경될 경우 에러메세지를 띄워줍니다.
덕분에 타입관련 버그들을 사전에 찾아 없앨 수 있습니다.

let 이름 :string[] = ['kim', 'park']
let 나이 :{ age : number } = { age : number }

array 혹은 object자료는 이렇게 타입지정이 가능합니다.

let 이름 :string | number = 'kim';

이 변수에 여러가지 타입의 데이터가 들어올 수 있다면 | 기호를 이용해 or 연산자를 표현할 수 있습니다. 위 예제는 변수에 숫자 혹은 문자를 집어넣을 수 있게 됩니다.

type nameType = string | number;
let 이름 :nameType = 'kim';

type 키워드를 이용해 타입을 변수처럼 담아서 사용가능합니다.

type NameType = 'kim' | 'park;
let 이름 :NameType = 'kim';

string number 이런 것 뿐만 아니라 나만의 타입을 만들어 사용가능합니다.
저렇게 원하는 글자나 숫자를 입력하면 이름이라는 변수엔 앞으로 'kim'또는 'park'만 들어올 수 있습니다. literal type이라고 부릅니다.

type을 써도 되고, interface를 써도 되고, 마음대로 해도 되는데 프로젝트에서 일관성만 유지하면 됩니다. A에서는 interface를 쓰고, B에서는 type을 쓰고 이런건 지양해야한다는 겁니다.

Tuple

튜플은 서로 다른 타입을 담을 수 있는 배열입니다. 튜플은 인덱스를 통해 접근해서 가독성이 떨어지므로 인터페이스, 타입 앨리어스(Type Alias)또는 클래스로 대체하여 사용하는 게 좋습니다.

let numberArray: number[] = [1,2,3]; // 배열
let tuple: [boolean, number, string] = [true, 1, 'Ok']; // 튜플

기본 타입

함수(Function)타입

함수의 매개변수 타입과 반환 타입을 함께 지정합니다.

function add(n1: number, n2: number): number {
  return n1 + n2;
}

Optional parameter는 반드시 전달해하지 않아도 되는 파라미터입니다.
매개변수 뒤에 물음표(?)와 콜론 기호(:)를 붙인 후 타입을 명시합니다.
타입스크립트가 제공하는 예약어로 특정 파라미터(인자)를 선택적으로
인자를 더 많이 쓰고 싶거나 생략하고 싶을 때 파라미터 뒤에 '?'를 붙인다.

// optional parameter
function printStr(str1: string, str2?: string) {
  console.log(str1, str2);
}

printStr('Type', 'Script'); // 출력결과: Type Script
printStr('Type'); // 출력결과: Type undefined

Default parameter는 값을 전달받지 않으면 기본 값을 설정받는 파라미터입니다.
타입을 명시한 후 기본 값을 명시합니다.

// Default parameter
function printStr(str: string = 'Type Script') {
  console.log(str);
}

printStr(); // 출력결과: Type Script

Rest parameter는 개수가 유동적인 파라미터입니다. 파라미터를 배열로 정의하면 됩니다.

// Rest parameter
function multiply(...nums: number[]): number {
  return nums.reduce((a, b) => a * b);
}

console.log(multiply(1, 2, 3, 4, 5));

배열(Array)타입

배열로 선언한 변수 뒤에 배열 타입을 명시합니다.

const nums: Array<number> = [1, 2, 3];
const script: string[] = ['JavaScript', 'TypeScript'];

함수 내에서 배열의 불변성을 유지하고 싶다면 readonly 키워드를 사용합니다.

function printStr(strs: readonly string[]) {
  console.log(strs);
  // strs.push('Error');
}

타입 앨리어스(Type Alias)

타입 앨리어스는 타입을 직접 정의할 수 있는 기능입니다.

// Object 타입 정의
type Num = {
  num: number;
  spelling: string,
}

const num1: Num = {
  num: 1,
  spelling: 'One',
}

console.log(num1.num, num1.spelling);

String Literal Type

String Literal Type은 특정 문자열만 지정할 수 있도록 정의합니다.

type TYPESCRIPT = 'TYPESCRIPT';
const typescript: TYPESCRIPT = 'TYPESCRIPT'; // TYPESCRIPT라는 문자열 값만 지정 가능

interface로 Object를 인자로 받기

한 개의 Object로 나타내고 싶다면 interface를 정의하고 사용해야 한다. 이렇게 하면 함수의 정의 부분에서도 각 변수를 object형태로 나타내주어야 한다.
(person.name, person.age, person.gender). interface의 이름은 대문자로 시작해야한다.

호출할 객체를 person으로 정의하고, 그 person의 속성들의 타입을 interface Person으로 정의하였다. 그리고 함수 정의 시에 petson:Person으로 인자를 호출하였다. 즉 interface를 작성하고 그것을 마치 원래 있던 type처럼 사용하는 것이다.

모든 속성값이 필수로 리턴되어야 한다.
만약 함수의 리턴값을 Person 형태로 한다면, 리턴값에 name,age,gender가 모두 포함되어야만 한다. 하나라도 빼고 싶다면, 각 속성값 뒤에 물음표(?)를 붙여주어 선택적인 값으로 처리해주어야 한다.

JavaScript vs TypeScript 파라미터 제한의 차이

// JS

function sum(a, b) {
  return a+b;
}

sum(10, 20, 30, 40); // 뒤의 숫자는 무시하고 10+20=30 의 결과만 가져온다


// TS

function sum(a: number, b: number) {
  return a+b;
}

sum(10, 20, 30, 40); // 숫자 2개의 인자만 와야함으로 오류 발생

인터페이스 vs 타입 별칭

interface Person {
  name: string;
  age: number;
}

type Person = {
  name: string;
  age: number;
 }

var ian: Person = {
  name: '이안',
  age: 28
}

인터페이스는 확장이 가능하지만 타입 별칭은 확장이 불가능하다.
그러므로 타입 별칭보다는 인터페이스를 사용하는 것을 추천한다.

유니온 타입 '|'

특정 타입을 '여러 개'쓸 수 있게 해준다.

function logMessage(value: string | number) {
  console.log(value);
}
logMessage('Hi');
logMessage(100);

파라미터를 찍으면 해당하는 차입의 API를 자동완성을 통해 쉽게 이용할 수 있다.

var todo: string | number | boolean;

function logMessage(value: string | number) {
  if (typeof value === 'number') {
    value.toLocaleString();
  }
  if (typeof value === 'string') {
    value.toString();
  }
  throw new TypeError('value must be string or number');
}

유니온 타입이 인터페이스들을 연결했을 때 '공통된 속성'만 접근이 가능하다.

interface Developer {
  name: string;
  skill: string;
}

interface Person {
  name: string;
  age: number;
}

function askSomeone(someone: Developer | Person) {
  someone.name //공통 속성만(보장된 속성만) 가능
  // 에러가 날 수 있어 타입 검증이 필요하므로 불가능
  //someone.skill
  //someone.age
}

인터섹션 타입 '&'

유니온 타입과 달리 갖고있는 모든 속성의 타입을 '포함'시킨다.

interface Developer {
  name: string;
  skill: string;
}

interface Person {
  name: string;
  age: number;
}

function askSomeone(someone: Developer & Person) {
  someone.name
  someone.skill
  someone.age
}

유니온 타입 vs 인터섹션 타입

아래의 예시에서 유니온 타입은 Developer 파라미터나 Person 파라미터가 들어가면 되지만,

인터섹션 타입은 Developer, Person 파라미터 속성 모두 합쳐서(name, skill, age) 들어가야 한다.

interface Developer {
  name: string;
  skill: string;
}

interface Person {
  name: string;
  age: number;
}

// 유니온 타입
function askSomeone(someone: Developer | Person) {
}
askSomeone({ name: '개발자', skill: '타입스크립트'});
askSomeone({ name: '이안', age: 28 });


// 인터섹션 타입
function askSomeone(someone: Developer & Person) {
}
askSomeone({ name: '이안', age: 28, skill: '타입스크립트'}); // 하나라도 누락시 오류

자바스크립트와 타입스크립트 차이

자바스크립트 객체 타입 = 키와 값을 중괄호로
타입스크립트 객체 타입 = 키와 타입을 중괄호로

그리고 타입스크립트 객체 타입은 쉼표(,)로 속성을 나누는 것이 아니라.
세미콜론(;)으로 나눈다는 것이 차이점입니다.

자바스크립트는 '동적인 타입'
타입스크립트는 '정적인 타입'

profile
프론트엔드 개발자를 꿈꾸는 도화지 위를 달리는 여자

0개의 댓글