자바스크립트 종류
1. 표준 자바스크립트인 ES5
2. ESNext,
3. ESNext에 타입 기능을 추가한 타입스크립트
타입스크립트로 개발했더라도 타입 기능을 사용하지 않는다면 ESNext 소스나 마찬가지임
javascript의 문제점
- JavaScript의 동일 연산자는 (==) 인수를 강제로 변환하여(coerces), 예기치 않은 동작을 유발
if ("" == 0) {
// 참입니다! 근데 왜??
}
if (1 < x < 3) {
// *어떤* x 값이던 참입니다!
}
- JavaScript는 또한 존재하지 않는 프로퍼티의 접근을 허용
const obj = { width: 10, height: 15 };
const area = obj.width * obj.heigth;
// area값은 NaN으로 뜸 -> height 철자 틀렸기 때문
대부분의 프로그래밍 언어는 이런 종류의 오류들이 발생하면 오류를 표출해주고, 일부는 코드가 실행되기 전인 컴파일 중에 오류를 표출해준다
수백 또는 수천 줄의 어플리케이션들을 작성할 때는 이러한 오류를 잡지 않는 것(javascript)은 심각한 문제가 된다.
TypeScript: 정적 타입 검사자 (TypeScript: A Static Type Checker)
정적 검사 : 프로그램을 실행시키지 않으면서 코드의 오류를 검출하는 것
정적 타입 검사 : 어떤것이 오류인지와 어떤 것이 연산되는 값에 기인하지 않음을 정하는 것
TypeScript는 JavaScript와 어떤 관계일까?
1. 구문 (Syntax)
구문 : 프로그램을 만들기 위해 코드를 작성하는 방법
TypeScript는 JS의 구문이 허용되는, JavaScript의 상위 집합 언어이다
// @errors: 1005 (")"이 없으므로 구문 오류)
let a = (4
→ 즉, 어떻게 작성돼있는지 모르지만 작동하는 JavaScript 코드를 TypeScript 파일에 넣어도 잘 작동합니다.
2. 타입 (Types)
TypeScript는 다른 종류의 값들을 사용할 수 있는 방법이 추가된, 타입이 있는 상위 집합이다.
위의 obj.heigth 오류는 구문 오류가 아닌, 값의 종류(타입)를 잘못 사용해서 생긴 오류이다
아래와 같은 JavaScript 코드가 브라우저에서 실행될 때, JavaScript에서 NaN을 출력합니다.
console.log(4 / []);
그러나 TypeScript는 배열로 숫자를 나누는 연산이 옳지 않다고 판단하고 오류를 발생시킨다.
TypeScript의 타입 검사자는 일반적인 오류를 최대한 많이 검출하면서 올바른 프로그램을 만들 수 있게 설계되어있다.
3. 런타임 특성 (Runtime Behavior)
TypeScript는 JavaScript의 런타임 특성을 가진 프로그래밍 언어이다
예를 들어, JavaScript에서 0으로 나누는 행동은 런타임 예외로 처리하지 않고 Infinity값을 반환합니다.
논리적으로, TypeScript는 JavaScript 코드의 런타임 특성을 호환성을 유지하기 위해 절대 변화시키지 않습니다.
즉 , TypeScript가 코드에 타입 오류가 있음을 검출해도, JavaScript 코드를 TypeScript로 이동시키는 것은 같은 방식으로 실행시킬 것을 보장한다.
이러한 특성은 TypeScript가 JavaScript 생태계와의 호환성을 유지하면서 코드의 안정성과 가독성을 향상시킬 수 있도록 도와준다.
4. 삭제된 타입 (Erased Types)
TypeScript의 컴파일러가 코드 검사를 마치면 타입을 삭제해서 결과적으로 “컴파일된” 코드를 만든다. 즉 코드가 한 번 컴파일되면, 결과로 나온 일반 JS 코드에는 타입 정보가 없다.
타입 정보가 없는 것은 TypeScript가 추론한 타입에 따라 프로그램의 특성을 변화시키지 않는다는 의미이다. 결론적으로 컴파일 도중에는 타입 오류가 표출될 수 있지만, 타입 시스템 자체는 프로그램이 실행될 때 작동하는 방식과 관련이 없다.
TypeScript 고유의 문법
1. 타입 추론 (Types by Inference)
TypeScript는 JavaScript 언어를 알고 있으며 대부분의 경우 타입을 생성해준다.
예를 들어 변수를 생성하면서 동시에 특정 값에 할당하는 경우, TypeScript는 그 값을 해당 변수의 타입으로 사용할 것입니다.
let helloWorld = "Hello World";
이것이 위의 예제에서 TypeScript가 helloWorld가 string임을 알게 되는 방식이다
2.타입 정의하기 (Defining Types)
JavaScript는 다양한 디자인 패턴을 가능하게 하는 동적 언어이다. 몇몇 디자인 패턴은 자동으로 타입을 제공하기 힘들 수 있는데 (동적 프로그래밍을 사용하고 있을 것이기 때문에) 이러한 경우에 TypeScript는 TypeScript에게 타입이 무엇이 되어야 하는지 명시 가능한 JavaScript 언어의 확장을 지원한다.
interface User {
name: string;
id: number;
}
const user: User = {
name: "Hayes",
id: 0,
};
객체의 형태를 명시적으로 나타내기 위해서는 interface 로 선언한다.
' : TypeName'의 구문을 사용해 JavaScript 객체가 새로운 interface의 형태를 따르고 있음을 선언한다.
다음은 name: string과 id: number을 포함하는 추론 타입을 가진 객체를 생성하는 예제입니다.
3. 타입 구성 (Composing Types)
여러가지 타입을 이용하여 새 타입을 작성하기 위해 일상적인 코드에서 가장 많이 사용되는 두 가지 코드로는 유니언(Union)과 제네릭(Generic)이 있다.
- 유니언 (Unions)
유니언 : 타입이 여러 타입 중 하나일 수 있음을 선언하는 방법.
type MyBool = true | false; // 예를 들어, boolean 타입을 true 또는 false로 설명할 수 있다
유니언 타입이 가장 많이 사용된 사례 중 하나는 값이 다음과 같이 허용되는 string 또는 number의 리터럴 집합을 설명하는 것이다.
type WindowStates = "open" | "closed" | "minimized";
type LockStates = "locked" | "unlocked";
type OddNumbersUnderTen = 1 | 3 | 5 | 7 | 9;
유니언은 다양한 타입을 처리하는 방법을 제공하는데, 예를 들어 array 또는 string을 받는 함수가 있을 수 있습니다.
function getLength(obj: string | string[]) {
return obj.length;
}
예를 들어, typeof obj === "string"을 이용하여 string과 array를 구분할 수 있으며 TypeScript는 객체가 다른 코드 경로에 있음을 알게 됩니다.
- 제네릭 (Generics)
제네릭 : 타입에 변수를 제공하는 방법
제네릭 타입 : 다양한 타입을 한꺼번에 취급할 수 있게 해준다.
배열이 일반적인 예시이며, 제네릭이 없는 배열은 어떤 것이든 포함할 수 있다. 제네릭이 있는 배열은 배열 안의 값을 설명할 수 있다.
type StringArray = Array<string>;
type NumberArray = Array<number>;
type ObjectWithNameArray = Array<{ name: string }>;
이 클래스는 여러가지 타입을 대상으로 동작할 수 있는데 이를 '제네릭 타입'이라고 한다.
class Container<T> {
constructor(public value: T) {}
}
let numberContainer: Container<number> = new Container<number>(1)
let stringContainer: Container<string> = new Container<string>('Hello world')
4. 구조적 타입 시스템 (Structural Type System)
TypeScript의 핵심 원칙 중 하나는 타입 검사가 값이 있는 형태에 집중한다는 것이다.
이는 때때로 “덕 타이핑(duck typing)” 또는 “구조적 타이핑” 이라고 불린다.
구조적 타입 시스템에서 두 객체가 같은 형태를 가지면 같은 것으로 간주됩니다.
interface Point {
x: number;
y: number;
}
function printPoint(p: Point) {
console.log(`${p.x}, ${p.y}`);
}
// "12, 26"를 출력합니다
const point = { x: 12, y: 26 };
printPoint(point);
point변수는 Point타입으로 선언된 적이 없지만 TypeScript는 타입 검사에서 point의 형태와 Point의 형태를 비교한 후 같은 형태이기 때문에 통과한다. 형태 일치에는 일치시킬 객체의 필드의 하위 집합만 필요하다.
interface Point {
x: number;
y: number;
}
function printPoint(p: Point) {
console.log(`${p.x}, ${p.y}`);
}
const point3 = { x: 12, y: 26, z: 89 };
printPoint(point3); // prints "12, 26"
const rect = { x: 33, y: 3, width: 30, height: 80 };
printPoint(rect); // prints "33, 3"
const color = { hex: "#187ABF" };
printPoint(color);
마지막으로 구조적으로 클래스와 객체가 형태를 따르는 방법에는 차이가 없다
'TypeScript' 카테고리의 다른 글
[TS] Typescript #day3 (2) | 2024.12.18 |
---|---|
[TS] Typescript #day2 (2) | 2024.12.18 |
[TS] Typescript #day1 (2) | 2024.12.16 |
[Error] addCase cannot be called with two reducers for the same action type (2) | 2023.11.23 |