Typescript 기초

김대은·2022년 10월 20일
0

Typescript

  • 메인 룰: typescript는 최종적으로 javascript로 변환된다.
  • typescript는 언어이자 컴파일러(tsc)이다. 컴파일러는 ts 코드를 js로 바꿔준다.
  • tsc는 tsconfig.json(tsc --init 시 생성)에 따라 ts 코드를 js(tsc 시 생성)로 바꿔준다. 인풋인 ts와 아웃풋인 js 모두에 영향을 끼치므로 tsconfig.json 설정을 반드시 봐야한다.
  • 단순히 타입 검사만 하고싶다면 tsc --noEmit 하면 된다.
  • 개인 의견: tsconfig.json에서 그냥 esModuleInterop: true, strict: true 두 개만 주로 켜놓는 편. strict: true가 핵심임.
    • allowJs :true ( ts와 js동시에 사용가능)
    • target: "es2016" (tsc가 코드를 변환 할 대상)
    • forceConsistentCasingInFileNames: true (import 시 대,소문자 구분해서 적용됨)
    • skipLibCheck (안쓰는 라이브러리 타입체크 패스하기)
  • ts 파일을 실행하는 게 아니라 결과물인 js를 실행해야 한다.

TS 문법

Js to Ts

  • 기본적으로 JS에 변수,속성,매개변수, 리턴값에 타입을 붙이면 TS
  • 소문자를 사용하여 타입기입
const a: number = 5;
function add(x: number, y: number): number { return x + y }
const add: (x: number, y: number) => number = (x, y) => x + y;
const obj: { lat: number, lon: number } = { lat: 37.5, lon: 127.5 };

타입 별칭

type Add =(x:number,y:number) => number
const add:Add=(x,y) => x+y

Interface

interface Add{
   (x:number,y:number):number
}
const add: Add = (x,y) => x+y

타입 별칭과 interface의 차이

배열,튜플 문법

튜플이란 ? 길이가 고정된 배열

let arr: string[] = [];
let arr2: Array<string> = [];
function rest(...args: string[]) {}

const tuple: [string, number] = ['1', 1];
tuple[2] = 'hello';
tuple.push('hello');

고정된 원시값 타입 ( 리터럴 타입)

const의 경우 바뀔 일이 없어 고정된 원시값으로 타이핑을 하여
정확한 타입을 기입 가능

const a: true =true;
const b: 5 = 5;
const b = 6 //error
const req = { url: "https://example.com", method: "GET" };
handleRequest(req.url, req.method);
//Argument of type 'string' is not assignable to parameter of type '"GET" | "POST"'.

// 수정 
const req = { url: "https://example.com", method: "GET" } as const;
handleRequest(req.url, req.method);

as

앞의 타입을 강제로 다른 타입으로 바꿈
가급적 비사용을 추천

const aa =123
aa= 'hello' as unknown as number


never

never관련 좋은 글
빈 배열은 never[]로 나오는데 이 경우 아무것도 넣을 수 없다.

! (non-null assertion)

null 또는 undefined가 아님을 개발자가 보증한다. 라는 의미로 보면된다


  • 최대한 ! 대신 if를 사용할 것
const head = document.querySelector('#head')!;
console.log(head);

const head = document.querySelector('#head');
if (head) {
  console.log(head);
}

템플릿 리터럴 타입

type World = 'world';

type Greeting = `hello ${World}`;

keyof , typeof

Key만 뽑아내고 싶다 ? keyof
자바스크립트 원형을 타입으로 쓰고 싶다? typeof

const obj = {a:'123',b:'hello',c:'world'};
type Key = keyof typeof obj // 'a'|'b'|'c'
type Value = typeof obj[keyof typeof obj] // '123'|'hello'|'world'

union(|), intersection(&)

union|은 'or' , ||의 의미와 같고 (하나라도 있으면 된다)
intersection&은 'and' &&의 의미와 같다. (모든 속성이 있어야한다)

function add(x:string | number, y:string| number):string | number {return x+ y}

add(1,2)
add('1','2')
add(1,'2')

단, 타입은 모든 경우의 수를 다 고려하기 때문에
위의 경우 x:string y:number와 같은 경우 까지 고려한다.

type Alias , interface extends

type Animal = {breath :true};
type Mammal = Animal & {breed:true};
type Human = Mammal & {think :true};

const a: Human ={breath:true, breed:true,think:true}
interface A {
 breath:true
}
interface B extends A {
 breed:true
}

const b: B ={breat:true, breed:true}

interface는 재선언이 가능하며,
재 선언시 기존 타입과 합쳐진다.
이 특징을 기반으로 다른 사람의 라이브러리 코드를 수정하여 사용할 수 도 있다.

좁은 타입과 넓은 타입

type A = string | number
type B = string

위 코드 중 type A가 type B에 비하여 더 넓은 타입을 가진다.

좁은타입에서 넓은 타입으로는 대입이 가능하지만,
넓은타입에서 좁은 타입으로는 대입이 불가능하다.

type A = {name:string};
type B = {age:number};

type C = {name:string, age:number}; // A & B

위의 경우는 type C가 가장 좁은 타입이다.
쉽게 말해 더 구체적일 수록 좁은 타입이다.

잉여 속성 체크,구조적 서브타이핑

구조적 서브타이핑은 상위와 하위의 개념으로, 상위의 개념이 하위를 포함하고 있는 것이다.
구조적 서브타이핑에서는 하위가 다른 어떤 프로퍼티를 가지고 있는지 보단,
그저 상위의 프로터미만 가지고 있으면 된다.

하지만 잉여 속성 체크는 그에 반해 상위에 없는 프로퍼티를 가지면 에러를 발생시킨다.

이 둘의 발동 조건은 바로 객체 리터럴을 사용하냐, 안하냐의 차이다.

//잉여 속성 체크
interface A { a:string }
const obj1: A ={a: 'hello' b:'world'}. // error
// 구조적 서브 타이핑
const obj ={a: 'hello' b:'world'}
const obj1: A = obj //에러안남

void

void 타입은 return 값을 사용하지 않겠다 라는 뜻이다.
하지만 메서드나 매개변수에서는 리턴값이 사용이 가능하다.

function a(callback:()=>void): void {
  return '3' //error
  return undefined //pass
  return null /error
}
a(() => {
	return '3'
})
interface Human {
	talk:()=>void;
}
const human:Human = {
 	talk() {retrun 'abc'}
}

unknown

any는 모든 타입이 다 가능하며, 타입검사를 포기한다고 보면 될듯하고
unknown 은 지금은 타입을 잘 모르겠지만, 추후에 지정을 하겠다 라고 생각하시면 편합니다.

타입간 대입 가능 표


초록색 체크도 x 로 보시면 됩니다.

타입가드

function numOrStr(a: number | string) {
  if (typeof a === 'string') {
    a.split(',');  
  } else {
    a.toFixed(1);
  }
}

function numOrNumArr(a: number | number[]) {
  if (Array.isArray(a)) {
    a.slice(1);  
  } else {
    a.toFixed(1);
  }
}

type B = { type: 'b', bbb: string };
type C = { type: 'c', ccc: string };
type D = { type: 'd', ddd: string };
type A = B | C | D;
function typeCheck(a: A) {
  if (a.type === 'b') {
    a.bbb;
  } else if (a.type === 'c') {
    a.ccc;
  } else {
    a.ddd;
  }

is

is를 활용하면 타입을 구분해주는 커스텀 함수를 직접 만들 수 있습니다.

interface Cat { meow:number }
interface Dog { bow: number }
function catOrDog (a: Cat | Dog) : a is Dog{
// 타입 판별
	if((a as Cat).meow) { return false }
    return true;
}

function pet(a: Cat | Dog){
	if(catOrDog(a)){
    	console.log(a.bow)
    }
    if('meow' in a){
    	console.log(a.meow)
    }
}
const isRejected = (input: PromiseSettledResult<unknown>): input is PromiseRejectedResult => { return input.status === 'rejected'};
const isFulfilled = <T>(input: PromiseSettledResult<T>): input is PromiseFulfilledResult<T> =>{ return input.status === 'fulfilled' } ;

const promises = await Promise.allSettled([Promise.resolve('a'), Promise.resolve('b')]);
const errors = promises.filter(isRejected);

class

class 또한 타입으로 사용할 수 있다
단, 주의사항은 이 경우 클래스 자체가 아니라 인스턴스를 의미한다
클래스 자체의 타입은 type of 클래스 이다.

class A {
 aa() { }
}
class B {
 bb() { }
}

function aOrB(para: A|B){
if(param instanceof A){
  param.aa();
  }
}

aOrB(A) //error
aOr(new B()) 
interface A {
	readonly a: string;
   b: string;
}

class B implements A {
	private a: string = '123';
    protectd b: string = '456';
	c: string='wow';
    
    
    method(){ // 모두 가능
      console.log(this.a);
      console.log(this.b);
      console.log(this.c);
    }
}
class C extneds B { 
  method(){ 
      console.log(this.a); // 불가능
      console.log(this.b);
      console.log(this.c);
    }
} 

new C().a; // 접근 불가
new C().b; // 접근 불가
new C().c; //  접근 가능
  • implements : 구현하다 는 의미로 interface를 따른다
  • private : 안에서는 사용 가능하지만 , 밖에서는 불가능.
  • protected : private과 비슷하지만, 상속의 경우 사용 가능
publicprotectedprivate
클래스 내부가능가능가능
인스턴스가능불가능불가능
상속 클래스가능가능불가능

단, 자바스크립트로 변환시 모두 사라지게된다.

readonly

readonly는 말 그대로 읽기 전용 속성이라 속성이 바뀌는것을 막을 수 있다.

inteface A {
 readonly a: string;
 b: string;
}
const aa :A {a:'hello' ,b: 'world'};
aa.a = '123' //error

인덱스드 시그니처

어떤 값 , 수 이든 상관없이 전부 특정 타입이길 원할 때

type A = { [key: string] : number }

맵드 타입스

type B ='Human'|'Mammal'|'Animal'
type A = { [key in B] : number }

옵셔널

function abc (a:number, b?:number, c?:number){ }
abc(1)
abc(1,2)
abc(1,2,3)
abc(1,2,3,4)//error

제네릭

제네릭은 타입에 대한 함수라고 생각하면 된다.

function add<T>(x: T, y: T): T { return x + y }
add<number>(1, 2);
add(1, 2);
add<string>('1', '2');
add('1', '2');
add(1, '2'); // error
profile
매일 1% 이상 씩 성장하기

0개의 댓글