
안정성때문이다. 코드를 작성할 때 타입 체크를 통해 버그가 줄어들고 개발자 경험을 좋게 만들어준다. 따라서 런타임 에러가 줄어들고 결국엔 생산성도 높인다.
ex 1)
[1,2,3,4]+false // 결과 : 1,2,3,4false
너무 flexible 한 나머지 위와 같은 이상한 코드를 허용한다.
ex 2)
const add = (a,b) => return a+b;
const result = add(1);
a,b 두개의 값이 필요하지만 a값만 넘겨도 오류가 발생하지 않는다.
이러한 런타임 에러는 코드를 실행하기 전에 오류가 발생한다는 것을 알려주는 것이 이상적이다. 그래서 코드를 실행하기전에 오류를 잡아내자라는 목표로 typescript가 등장하게 되었다.
typescript = strongly typed 프로그래밍 언어이다.
typescript에서 코드를 확인하고 컴파일 과정에서 에러가 있다면 컴파일을 하지 않고 에러가 없다면 javascript로 코드를 변환한다.
const 변수명 : type = ... 형태
type Player = {
name:string,
age?:number //optional
}
const playerOne:Player = {name:'one'} //type Player 사용
const playerTwo:Plyer = {name:'two', age:12}
//함수
function playerMaker (name:string):Plyaer{ //return 타입이 Player
return {name}
}
//화살표 함수
const playerMaker = (name:string):Player=>({name});
const chaeyeon = playerMaker('chaeyeon');
yeon.age=12;
const numbers:readonly number[]=[1,2,3,4]
numbers.push(1) //에러 발생
array내 type이 다를 때 사용
const player:[string,number,boolean] = ['yeon',24,true]
typescript의 제약에서 빠져나오고 싶을 때 사용. typescript의 보호장치를 비활성화 한다.
cosnt a:any[]=[1,2,3,4]
const b:any=true
a+b //오류 발생하지 않음
변수의 타입을 미리 알지 못할 때 사용
let a:unknown;
if(typeof a==='number') let b = a+1;
if(typeof a==='string') a.toUpperCase();
아무것도 return하지않을 때 사용하지만 꼭 써줄 필요없이 생략가능하다
function hello():void{
console.log('x');
}
함수가 절대 return값이 없을 때 사용한다.
function hello(name:string|number):never{
throw new Error('X');
}
//call signature 없이
//이 함수는 number type을 return 한다.
const add =(a:number, b:number)=> a+b;
//call signature 사용
type Add = (a:number, b:number)=>number;
const add:Add = (a,b)=> a+b;
함수를 구현하기 전에 타입을 만들고 함수가 어떻게 작동하는지 서술 가능.
코드를 짤 때 함수의 타입을 설명하고 코드룰 구현하면서 프로그램을 디자인할 때 타입을 먼저 생각하고 분리해서 구현이 가능하다.
다른 사람이 만든 외부 라이브러리를 사용할 때 오버로딩을 많이 사용한다.
오버로딩은 함수가 서로 다른 여러개의 call signatures를 가지고 있을 때 발생한다.
//param 타입이 다를 때
type Add = {
(a:number, b:number):number,
(a:number, b:string):number
}
const add:Add=(a,b)=>{
if(type of b==='string') return a;
return a+b;
}
//param 갯수가 다를 때
type Add = {
(a:number, b:number):number,
(a:number, b:number, c:number):number //여기서 c는 option이 된다.
}
const add:Add=(a,b,c?:number)=>{
if(c) return a+b+c;
return a+b;
}
polymorphism = many+structure => 여러가지 다른 형태
//배열을 받고 배열의 요소를 하나씩 print하는 함수
type SuperPrint = {
(arr:number[]):void
(arr:boolean[]):void
(arr:string[]):void
...
}
const superPrint:SuperPrint=(arr)=>{
arr.forEach(i=>console.log(i))
}
superPrint([1,2,3,4]);
superPrint([true,false]);
superPrint(['1','2','3']);
위의 코드에서 배열이 number인지 boolean인지... 모든 type에 대해 작성하는 것은 비효율적이다. 이때 generic type을 사용할 수 있다.
type SuperPrint = {
//<Generic>, <T>, <V> ... 아무거나 사용가능 하다
<TypePlaceholder>(arr:typePlaceholder[]):void
}
const superPrint:SuperPrint=(arr)=>{
arr.forEach(i=>console.log(i))
}
superPrint([1,2,3,4]);
superPrint([true,false]);
superPrint(['1','2','3']);
generic은 call signature를 작성할 때 들어올 확실한 타입을 모를 때 사용할 수 있다. generic을 이용해서 작성하면 typescript가 자동으로 타입을 유추한다.
generic과 any의 다른점은 generic은 타입스크립트의 보호를 받지만 any는 받지않는 다는 것이다.
generic은 개발자가 요구한 대로 signature를 생성하게 해주는 도구이다.
//generic 여러개 사용하기
type SuperPrint= {
<T, M>(a:T[],b:M):T
}
const superPrint:SuperPrint=(a,b)=>{
return a[0];
}
const a = superPrint([1,2,3,4], 'x');
//type 확장하기
type Player<E>={
name:string
extraInfo:E
}
type Extra={
age:number
}
type exPlayer = Player<Extra>
const yeon:exPlayer={
name:'chaeyeon',
extraInfo:{
age:24
}
}