코로 넘어져도 헤딩만 하면 그만

Typescript 들어가기 전 주말공부 본문

CODE STATES 44

Typescript 들어가기 전 주말공부

꼬드리 2023. 5. 28. 14:35

Typescript는 javascript 개선한 업그레이드 버전이라고 보면 된다. 따로 타입을 지정 안 해도 되는 포용력이 과하게 높은 자바 스크립트보다, strict하게 에러를 잡아주는 타입 스크립트의 중요성이 높아진다. 

 

1) 자바스크립트는 dynamic typing 가능하기 때문에 5-'3'도 계산이 가능하다. 그러나 프로젝트 사이즈가 커지게 되면 이러한 자유도는 단점이 될 뿐이다. 타입 스크립트에서는 type error을 쓰면 이상하다고 말해준다. 

2) 타입 스크립트로 엄격하게 타입을 체크하면서, 에러 메세지의 퀼리티가 올라가게 된다. 

 

"자바스크립트가 아직까지 살아 남은 이유는 타입 스크립트가 산소 호흡기를 붙여두었기 때문이다."

-개발자 선배님 왈

 

 

🚩Typescript 적용하기

1) 파일은 무조건 .ts 파일로 생성해야 한다. 이 .ts파일은 못 읽히기 때문에 .js로 컴파일 해야 사용가능하다. new terminal에 tsc - w 라는 명령어를 입력하면 자동으로 js로 전환된다. 이걸 끄지 않으면 js가 생성되는 것을 볼 수 있다. html에 꽂으려면 js를 쓰면 된다. 

2) tsconfig.json이라는 걸 생성한다. 아래 코드를 넣는다. js 몇 버전으로 컴파일 할 것인지 적어주는 것이다. 

{   
  "compilerOptions" : {     
    "outDir": "dist", //dist라는 폴더 안에 앞으로 js를 다 넣어 줘
    "target": "es5", //어떤 걸로 변환을 해줄래? es6도 가능    
    "module": "commonjs", //일반적인 js. React면 esnext
  } 
}

cmd+shift+B

 

변수를 만들 때에는 let 이름: string = 'kim'; 이렇게 타입을 지정해줘야 한다. 이 변수에는 문자만 들어올 수 있다는 의미. 타입을 엄격하게 관리한다. 숫자가 들어오면 에러가 바로 난다. 

배열은 let 이름 : string[] = ['kim', 'park']; 이 내부에는 string만 들어오는 array라는 엄격한 뜻.

let 이름: Array<string>=['kim' , 'park']; 이런 식으로 표현도 가능하다. 

 

객체는 let 이름 : {name : string } = {name : 'kim'};

name?를 하면 들어올 수도 있고 아닐 수도 있다는 뜻.

타입 스크립트에서는 아래와 같이 타입을 일일이 지정해준다.

웬만해서는 any 타입은 잘 쓰지 않는다....(이거 쓰면 뭐하러 타입 스크립트 씀?)

 

let 이름: string | number = 'kim'; //문자나 숫자가 들어올 수 있습니다.

type Mine = string | number; //이렇게 그냥 변수로 넣어서 쓸수도 있다. 대문자로 시작.

function 함수(x: number) : number {
	return x * 2
} //number가 들어오고, number가 리턴되어야 한다.

type Member = [number, boolean];
let john: Member = [];
//무조건 첫째는 number, 둘째는 boolean이 들어와야 한다.

 

type Member = {
	name : string
    }
   let john : Member = {name : 'kim'};
 //무조건 문자만 들어오게 된다.
 
 type Member = {
	[key: string] : string
    }
   let john : Member = {name : 'kim', age : '3'};
 //이런 식으로 모두에게 적용 가능
 
 class User {
 	name: string;
    constructor(name: string){
     this.name = name;
    }
 }

 

 

하여간에 타입 스크립트는 정적 타입 언어이다. Java같이...

void는 아무것도 반환하지 않는 함수.(ex 콘솔만 찍음)

never은 영원히 끝나지 않거나 항상 에러를 반환하는 함수의 타입으로 씀. 

enum은 비슷한 값들끼리 묶어준다. 

 

 

🚩인터페이스 interface

type Score = 'A' | 'B' | 'C' | 'D' ;

interface User {
	name: string;
    age: number;
    gender?: string;
    readonly birthYear: number; //수정불가능
    [key: number] : Score; //학년별 ? 적어줄 필요 없이 이렇게 키 설정 가능
}

let user : User = {
	name: 'xx',
    age: 30,
    birthYear: 2000,
}

 

🚩인터페이스로 함수 정의하기

interface Add {
	(num1: number, num2: number): number;
}

const add: Add = function(x, y) {
	return x + y ;
}

// add (10, 20)


interface IsAdult {
	(age: number): boolean;
}
const a:IsAdult = (age) => {
	return age > 19;
}
a(33) // true

 

🚩인터페이스로 클래스 정의하기

//implements

interface Car {
	color: string;
    wheels: number;
    start(): void;
}

class Bmw implements Car {
	color;
    wheels=4;
    constructor (c: string) {
    this.color = c;
    }
    start(){
    console.log('go')
    }
}

const b = new Bmw('green'){
console.log(b)
b.start();
}

//extends로 인터페이스 확장. 추가 가능.
interface Benz extends Car {
	door: number;
    stop(): void;
}

const benz: Benz = {
	door: 5,
    stop(){
    console.log('stop')
	},
    color: 'black',
    wheels: 4,
    start (){
    console.log('go...')}
}

 

function hello(name: string, age?: number): string { //age?가 먼저 앞에 와서는 안 된다. 
	if (age !== undefined){
    return `Hello, ${name}. You are ${age}.`
    } else {
    return `Hello, ${name}.`}
}

타입 스크립트에서는 this도 타입을 입력해줘야 한다. 

 

const userName1 = "Bob";
let userName2 : string | number = "Tom";
userName2=3;

type Job= "police" | "teacher";
interface User {
	name: string;
    job: Job;
}

const user : User = {
	name: "Bob",
    job: "teacher",
};

interface HighSchoolStudent {
	name: number | string;
    grade : 1|2|3;
}

 

🚩접근 제한자 public, private, protected

아무것도 작성하지 않으면 전부 public이다. 

private는 자식 클래스 내부에서 사용할 수 없다.(#만 적기도 함)

protected는 자식 클래스에서는 참조 가능하지만 클래스 인스턴스에서는 참조 불가하다.

 

 

타입이 여러 개인데 전부 나열해 적는 게 비효율적일 때. Genetic을 사용한다. <> 로...

function getSize<T>(arr:T[]): number {
return arr.length;
}

const arr1 = [1,2,3];
getSize<number>(arr1);

const arr2=["a","b","c"];
getSize<string>(arr2);

//Genetic 의 역할, 하위에서 타입을 지정할 수 있게 해줌 <>

 

아래와 같이 인터페이스로 사용할 수도 있다. 

interface Mobile<T> {
	name: string;
    price: number;
    option: T;
}

const m1: Mobile<{color: string; coupon: boolean}> ={
	name: "s21",
    price: 1000,
    option: {
    	color: "red",
        coupon: false,
    }
}

const m2: Mobile<string> = {
	name: "s20",
    price: 900,
    option: "good",
}

 

 

🚩자주 사용되는 유틸리티 타입

Partial / Required / Readolny/ Record / Pick / Omit / Exclude / NonNullable

type Grade = "1" | "2" | "3" | "4";
type Score = "A" | "B" | "C" | "D" | "F";
const score: Record<Grade, Score> = {
	1: "A",
    2: "B",
    3: "D",
    4: "C",
};
//이런 식으로 Record <K,T> 처럼 키와 값을 사용할 수 있다.

interface User {
	id: number;
    name: string;
    age: number;    
}


//Pick과 Omit
const admin: Pick<User, "id" | "name"> = {
	id: 0,
    name: "Bob",
}

//Omit으로 바꾸면 제외가 가능함. 키를 제거.
//Exclude<T1, T2> 타입1에서 타입2를 제거
type T1 = string | number | boolean;
type T2= Exclude <T1, number | string>; //boolean

//NonNullable<Type>
type T1 = string | null | undefined | void;
type T2 = NonNullable<T1>; //string, void만 남는다.

 

React에서 타입 스크립트 쓰기

컴포넌트의 리턴값이 함수인 경우,

const App:React.FC = () => {
 ...
}
//이런 식으로 함수를 지정해줄 수 있다.

 

타입 스크립트는 원하는 모양으로 직접 타입을 만들어줄 수 있다. type / interface 로 만들어줄 수 있음. 두개 차이가 크게 있진 않은데. 하여튼. 

useState는 아래와 같이 타입을 지정 가능하다. 

const [myApp, setMyApp] = useState<number>(data);
//useState 쓸 때에는 Genetic 방식으로 설정해줄 수 있음.

 

보통 props 불러올 때에 받아온 것에 타입은 따로 준다. 

interface OwnProps {
	info: Restaurant, 
    changeAddress(address: Address):void, //리턴되는 값 없음
}
//이런 식으로 info와 changeAddress함수를 넘겨 받았을 때 props 타입을 지정 가능

interface는 반복되는 부분을 extends로, type는 &로 확장 가능. 단, 타입은 Omit 등을 사용해서 원하는 걸 쉽게 제외할 수 있다는 장점. 

 

 

다음 주 본격적으로 TypeScript를 배우기 전에 주말에 혼자 이거저거 보면서 정리해본 결과... 아직 부족하겠지만...

있다가 공식 문서도 한번 봐야겠다. 

Comments