TypeScript?

pingu·2023년 1월 28일
0

typescript

목록 보기
1/3


웹 프로그래밍 == javascript 기반
TypeScript === javascript 슈퍼셋
TypeScript > javascript
요즘은 javascript 대신 TypeScript를 많이 사용한다.
TypeScript 안쓰는 사람 = 나쁜 사람...ㅠ
이번 기회로 나쁜 사람 탈출해보자

TypeScript: 정적 타입 검사자

(TypeScript: A Static Type Checker)

javascript의 문법의 경우 연산자는 인수를 강제 변환하여, 예기치 않은 동작을 유발한다.

console.log(0 == "") // true

?

x = 4;
console.log(1<x<3) // true

??

또, 존재하지 않는 프로퍼티의 접근을 허용한다.

const obj = { width: 10, height: 15 };
console.log(obj.width) // 10
console.log(obj.heigth) // 15
const area = obj.width * obj.heigth;
console.log(area) // NaN

???

대부분의 프로그래밍 언어는 이런 종류의 오류들이 발생하면 오류를 표출해주고, 일부는 코드가 실행되기 전인 컴파일 중에 오류를 확인 할 수 있다. 작은 프로그램을 작성할 때에는 관리가 가능하지만 수백 또는 수천 줄의 어플리케이션들을 작성할 때에는 개발자 입장에서 골치가 아프다.

정적 타입 검사자인 TypeScript는 타입이 있는 JavaScript의 상위 집합이라 정의 할 수 있다.
TypeScript는 프로그램을 실행시키기 전에 값의 종류를 기반으로 프로그램의 오류를 찾는다. 예를 들어, 위의 마지막 예시에 오류가 있는 이유는 obj의 타입 때문이다.


타입(Types)

TypeScript는 다른 종류의 값들을 사용할 수 있는 방법이 추가된, 타입이 있는 상위 집합이다.

// @errors: 2551
const obj = { width: 10, height: 15 };
const area = obj.width * obj.heigth;

위 TypeScript 오류는 구문 오류가 아닌, 값의 종류(타입)를 잘못 사용해서 생긴 오류이다.

console.log(4 / []); //NaN
// @errors: 2363
console.log(4 / []);

실제로 어떤 일이 일어나는지 보려는 의도로 숫자를 배열로 나눌 수 있지만, 대부분은 프로그래밍 실수다. TypeScript의 타입 검사자는 일반적인 오류를 최대한 많이 검출하면서 올바른 프로그램을 만들 수 있게 설계되었다.

만약 JavaScript 파일의 코드를 TypeScript 코드로 옮기면, 코드를 어떻게 작성했는지에 따라 타입 오류를 볼 수 있다. 이는 코드 상의 문제이거나, TypeScript가 지나치게 깐깐한 것일 수 있다.
오류가 없는데 있다고 판단하는 색기는 두둘겨 패야함

런타임 특성 (Runtime Behavior)

TypeScript는 JavaScript의 런타임 특성을 가진 프로그래밍 언어이다.
예를 들어, JavaScript에서 0으로 나누는 행동은 런타임 예외로 처리하지 않고 Infinity값을 반환한다. 논리적으로, TypeScript는 JavaScript 코드의 런타임 특성을 절대 변화시키지 않는다.

즉, TypeScript가 코드에 타입 오류가 있음을 검출해도, JavaScript 코드를 TypeScript로 이동시키는 것은 같은 방식으로 실행시킨다

삭제된 타입 (Erased Types)

TypeScript의 컴파일러가 코드 검사를 마치면 타입을 삭제해서 결과적으로 "컴파일된" 코드를 만든다. 즉 코드가 한 번 컴파일되면, 결과로 나온 일반 JS 코드에는 타입 정보가 없다.

타입 정보가 없는 것은 TypeScript가 추론한 타입에 따라 프로그램의 특성을 변화시키지 않는다는 의미다. 결론적으로 컴파일 도중에는 타입 오류가 표출될 수 있지만, 타입 시스템 자체는 프로그램이 실행될 때 작동하는 방식과 관련이 없다.

TypeScript는 추가 런타임 라이브러리를 제공하지 않는다. TypeScript는 프로그램은 JavaScript 프로그램과 같은 표준 라이브러리 (또는 외부 라이브러리)를 사용하므로, TypeScript 관련 프레임워크는 필요가 없다.

타입 정의하기 (Defining Types)


위 코드는 문자열로 선언한 변수에 숫자를 넣어버렸는데 JavaScript는 컴파일하기 전까지는 뭐가 잘못되었는지 파악하지 못한다.

하지만 ts에선 타입이 잘못되었다고 미리 알려준다

문자열

let pingu : string = '핑구';
let fullName: string = `Bob Bobbington`;
let age: number = 37;
let sentence: string = "Hello, my name is " + fullName + ".\n\n" +
    "I'll be " + (age + 1) + " years old next month.";
// Hello, my name is Bob Bobbington. I'll be 38years old next month.

백틱으로 변수 안에 있는 값을 표현식에 포함하였던 문법을 위와같이 사용 가능하다.

불리언

let pingu : boolean = boolean;

숫자

let pingu : number = 9;
let decimal: number = 6;
let hex: number = 0xf00d;
let binary: number = 0b1010;
let octal: number = 0o744;

배열

let pingu : string[] = ['핑구', '핑가'];
let pingu : number[] = [ 9, 8 ];
let pingu : Array<number> = [1, 2, 3]; // 제네릭 배열 타입

객체

let pingu : { name : string, age : number} = { name : '핑구', age : 9};
let pingu : { name? : string, age : number} = { name : 999, age : 9};
declare function create(o: object | null): void;

create({ prop: 0 }); // 성공
create(null); // 성공

create(42); // 오류
create("string"); // 오류
create(false); // 오류
create(undefined); // 오류

타입

타입도 변수처럼 선언해서 사용이 가능하다.
선언 해놓고 변수에 타입 선언해줄 때 대신 넣어줄 수 있다.
주의) 타입명 맨앞에 대문자를 쓰던 뭘 해서 일반 변수명과 차이를 둬야할 것

type Name = string | number;
let pingu : Name = 123;

함수

function 함수( pingu : number) : number {
  // 함수 파라미터 pingu의 타입은 number이다.
  // 리턴값 타입은 number이다. 리턴값이 숫자 타입이 아닌 다른 타입이면 오류뜸
  return pingu * 2
}
//함수('123') << 오류

wrapInArray에 문자열이 들어가면 [obj]가 출력되고 배열이 들어가면 obj가 출력된다.

위와 같이 객체 키에 ?를 붙여주면 뒤에 나올 키의 타입을 지정해도 다른 타입을 넣을 수 있다.
어떤 타입의 데이터가 들어올지 모를땐 이렇게 표시해두자

tuple 타입

type Member = [boolean, number]; // 배열 0번째 타입은 불리언, 1번째 타입은 숫자
let pingu : Member = [true, 123];
pingu[1].concat('!'); // Error, 'number' does not have 'concat'
pingu[5] = 'hello'; // Error, Property '5' does not exist on type '[string, number]'.

만약 정의하지 않은 타입, 인덱스로 접근할 경우 오류남

클래스

class User{
  name : string; // 미리 변수 생성해서 타입 지정 해둘것
  constructor( name : string ){ // constructor 함수형 타입지정과 동일함
    this.name = name;
  }
}

열거 (Enum)

enum Color {Red = 1, Green, Blue = 4}
let colorName1 : string = Color[0];
console.log(colorName1); // Undefined
let colorName2 : string = Color[1];
console.log(colorName2); // Red
let colorName3 : string = Color[2];
console.log(colorName3); // Green
let colorName4 : string = Color[3];
console.log(colorName4); // Undefined
let colorName5 : string = Color[4];
console.log(colorName5); // Blue

any 타입

기존에 자바스크립트로 구현되어 있는 웹 서비스 코드에 타입스크립트를 점진적으로 적용할 때 활용하면 좋은 타입이다. 단어 의미 그대로 모든 타입에 대해서 허용한다는 의미를 갖고 있다.

let pingu : any = 123;
pingu = 'ㅇㅇ'

'귀찮으면 그냥 any 써라'
이럴거면 타입스크립트 왜 쓰냐

void

어떤 타입도 존재할 수 없음을 나타내기 때문에, any의 반대 타입 같다. 변수에는 undefined와 null만 할당하고, 보통 함수에서 반환 값이 없을 때 반환 타입을 표현하기 위해 쓰인다

let pingu : void = undefined;
function pinga() : void {
  console.log('sth');
}
let pingu: void = undefined;
pingu = null; // 성공  `--strictNullChecks` 을 사용하지 않을때만

Never

절대 발생할 수 없는 타입, 함수의 끝에 절대 도달하지 않는다는 의미를 지닌 타입이다.
예를 들어, never는 함수 표현식이나 화살표 함수 표현식에서 항상 오류를 발생시키거나 절대 반환하지 않는 반환 타입으로 쓰인다. 변수 또한 타입 가드에 의해 아무 타입도 얻지 못하게 좁혀지면 never 타입을 얻게 될 수 있다.

never타입은 모든 타입에 할당 가능한 하위 타입이다. 하지만 어떤 타입도 never에 할당할 수 있거나, 하위 타입이 아니다.(never 자신은 제외) 심지어 any 도 never에 할당할 수 없다.

// never를 반환하는 함수는 함수의 마지막에 도달할 수 없다.
function error(message: string): never {
    throw new Error(message);
}
// 반환 타입이 never로 추론된다.
function fail() {
    return error("Something failed");
}
// 이 함수는 절대 함수의 끝까지 실행되지 않는다는 의미
function neverEnd(): never {
    while (true) {
    }
}

Null and Undefined

TypeScript는 undefined 과 null 둘 다 각각 자신의 타입 이름으로 undefined , null로 사용한다. void처럼 그 자체로 유용한 경우는 거의 없다

// 이 밖에 이 변수들에 할당할 수 있는 값이 없다!
let u: undefined = undefined;
let n: null = null;

타입 구성 (Composing Types)

객체들을 조합하여 더 크고 복잡한 객체를 만드는 방법과 유사하게 TypeScript에 타입으로 이를 수행하는 도구가 있다. 여러가지 타입을 이용하여 새 타입을 작성하기 위해 일상적인 코드에서 가장 많이 사용되는 두 가지 코드로는 유니언(Union)과 제네릭(Generic)이 있다.

유니언 (Unions)

유니언은 타입이 여러 타입 중 하나일 수 있음을 선언하는 방법이다. 예를 들어, boolean 타입을 true 또는 false로 설명할 수 있다.

type MyBool = true | false; // type MyBool = boolean
let pingu : string | number = 123;
function 함수(obj: string | string[]){
  // 함수 파라미터 obj의 타입은 문자열과 배열(문자열)이다.
  if (typeof obj === "string") {
    return [obj];
  } 
  else {
    return obj;
  }
}

함수에 문자열이 들어가면 [obj]가 출력되고 배열이 들어가면 obj가 출력된다.

제네릭 (Generics)

제네릭은 타입에 변수를 제공하는 방법이다.

type StringArray = Array<string>;
type NumberArray = Array<number>;
type ObjectWithNameArray = Array<{ name: string }>;
// @errors: 2345
interface Backpack<Type> {
  add: (obj: Type) => void;
  get: () => Type;
}

// TypeScript에 `backpack`이라는 상수가 있음을 알리는 지름길이며
// const backpack: Backpack<string>이 어디서 왔는지 걱정할 필요가 없다.
declare const backpack: Backpack<string>;

// 위에서 Backpack의 변수 부분으로 선언해서, object는 string이다.
const object = backpack.get();

// backpack 변수가 string이므로, add 함수에 number를 전달할 수 없다.
backpack.add(23);

구조적 타입 시스템 (Structural Type System)

참고자료

https://typescript-kr.github.io/
https://joshua1988.github.io/ts/intro.html
https://www.youtube.com/watch?v=xkpcNolC270

profile
코딩공부 리뷰

0개의 댓글