생각기록
2023-03-22 [udemy] typeScript 강의 섹션2: 기본과 기본타입 본문
typeScript 많은 타입을 지니고있다.
Core Types
| number type | 1, 5.3, -10 | 정수든 실수든 number type입니다. |
| String | '안녕', "안녕", `안녕` | ``백틱은 일부 데이터 동적 주입할 수 있는 템플릿 리터럴을 작성 가능 |
| boolean | true, false | |
| object | {age: 30} | |
| Array | [1,2,3] | |
| Tuple | [1,2] | js에는 없다. 배열이 맞지만 길이가 고정된 배열 |
| Enum | enum { NEW, OLD } | js에 없다 / 열거 목록 제공 |
| Any | * | 모든 종류의 값 저장 가능 = 매우 유연함 |
템플릿 리터럴이란?
참고 : https://velog.io/@rlaghwns1995/JavaScript-%ED%85%9C%ED%94%8C%EB%A6%BF-%EB%A6%AC%ED%84%B0%EB%9F%B4
저번에 했던 프로젝트를 사용합시다
npm start로 서버 열어줍니다.

app.ts 파일의 내용을 지워줍니다.
핵심 데이터 타입
//app.ts
function add(n1, n2){
return n1 + n2;
}
const number1 = 5;
const number2 = 2.8;
const result = add(number1, number2);
console.log(result);
tsc app.ts로 컴파일합니다.

문제가 없죠

이부분을 문자열로 바꾼다면

이런식으로 찍힙니다.
올바른 결과로 나타나지 않음
string으로 문자열을 연결한 결과가 나왔다.
타입 배정 (type assignment) 을 매개변수에 추가
ts 는 매개변수의 타입이 무엇인지 지정해줄 수 있다.
function add(n1: number, n2: number){
return n1 + n2;
}
const number1 = 5;
const number2 = 2.8;
const result = add(number1, number2);
console.log(result);
app.ts 와 app.js가 동시에 열려있으면, 에러가 뜹니다
app.js파일을 닫아주면 됨!
중복 함수 구현과 관련된 IDE 에서 에러가 발생할 수 있기 때문

ts 타입 vs js 타입
Typeof 연산자


number라고 알려줍니다.
이것을 이용해 if문으로 오류처리도 가능!


콘솔에 해당 오류가 떠야 하는데,

저는 이렇게만 뜨네요 (인강은 떠요)
위에는 일반적인 js 코드입니다.
근데 전혀 이부분은 타입스크립트에서 필요하지 않다
js는 동적타입
- 즉 나중에 문자열을 할당해도 처음에 숫자형을 잡아둘 수 있는 변수가 있어도 문제가 없다
- 그래서 특정타입에 의존하는 코드가 있는 경우 런타임에서 확인하도록 하게 했음
- typeof 연산자를 사용하듯이
반면!
typeScript 는 정적타입
- 즉 개발 도중에 끝나는 변수와 매개변수의 타입을 정의해야 함
- 런타임중 변경 x

이따금 런타임에서 타입을 가져오는 것이 유용할 수 있겟지만, 이 예시처럼
개발 도중에 가져오는것이 훨씬 나을 때도 있습니다.
핵심 : 타입 케이스
타입스크립트에서는 항상 string 또는 number 와 같은 타입을 다룬다.
*중요 : string, number o / String, Numger x
타입스크립트의 주요 원시 타입은 모두 소문자입니다.
숫자 문자열 및 불리언 작업
js든 ts든 모든 숫자형은 기본적으로 float 실수형입니다.
5와 5.0 사이에는 차이가 없다.

이 비교의 결과는 boolean 입니다.
여기 3중 등호 !== 나 부등호는 참이나 거짓을 생성하는 연산자
function add(n1: number, n2: number, showResult: boolean){
// if( typeof n1 !== 'number' || typeof n2 !== 'number' ){
// throw new Error('Incorrect Input!'); // 잘못된 입력 (타입 오류 처리)
// }
// js는 boolean 타입이 오면 알아서 참인지 아닌지를 검사한다.
if(showResult) {
console.log(n1 + n2);
} else {
return n1 + n2;
}
}
const number1 = 5; // 5.0
const number2 = 2.8;
const printResult = true;
const result = add(number1, number2, printResult);

7번째라인
if 문 값이 참이여서 찍힌 콘솔값

function add(n1: number, n2: number, showResult: boolean, phrase: string){
// if( typeof n1 !== 'number' || typeof n2 !== 'number' ){
// throw new Error('Incorrect Input!'); // 잘못된 입력 (타입 오류 처리)
// }
// js는 boolean 타입이 오면 알아서 참인지 아닌지를 검사한다.
if(showResult) {
console.log(phrase + n1 + n2);
} else {
return n1 + n2;
}
}
const number1 = 5; // 5.0
const number2 = 2.8;
const printResult = true;
const resultPharae = 'Result id : ';
const result = add(number1, number2, printResult, resultPharae);
두 숫자형과 결합한 문자열을 만들어 오류가 났다.

이유는?

phrase 때문에 모두 문자열로 변환이 된다.
이 함수에서 이를 피하기 위해서는

이런식으로 하면, 문자열과 같이 계산되지 않으므로 숫자형으로 인식됩니다.

타입할당 및 타입 추론하기
매개변수 이름 : 타입
타입 배정은 ts만 이해가 가능 / js는 이해하지 못합니다.

그처럼 타입추론(type inference)라는 내장기능도 쓰고 있습니다.
즉, 특정 변수나 상수에 어떤 타입을 사용했는지를 ts는 아주 잘 이해하고 있다.
const number1 = 5;
number1을 항상 숫자형이라고 이해한다
여기서 식별되는 타입은 아무 숫자형이 아닌, 5라는 상수 값


let으로 해도 number라고 인지하고 있다.
좋지 않은 방법

이미 ts가 number타입이라고 타입추론이 가능하며, 값이 상수인 5여서 타입 배정을 해주는 것은 좋지 않습니다.
이런 경우가 좋다

지정하지 않은 방식으로 이 변수를 생성하는 경우에만 변경
이처럼 처음부터 설정하지 않으면, 나중에 값을 지정할 때 어떤 값을 저장할지 ts에게 알려주는 것이 좋다.
퀴즈



객체 형태

기존파일 basic.ts로 rename하고 app.ts파일 새로 만들기



person에 저장된 데이터의 타입이라고 추론하고 있다.
js의 객체처럼 보이지만, 차이점은
, (쉼표) x ; (세미콜론) o을 쓰고있다
js는 키와 값을 작성하지만
ts는 키와 타입을 입력
객체 타입은 어딘가에서 사용되는 객체 타입을 설명하기 위해 작성되는 것
객체 지정하는 법
- 중괄호 { }
- 그 안에 키와 타입을 지정

하지만 이방법은 좋지 않고
앞서 우리가 배웠던 방법으로 ts를 이해시키는 것이 좋다

이 형태가 더 나은 구문
중첩된 개체 및 타입
물론 객체 타입은 중첩 객체에 대해서도 생성 가능
다음과 같은 js 객체가 있다고 가정

이러한 객체의 타입은 아래와 같다

따라서 객체 타입 안에 객체 타입이 있다고 말할 수 있다.
배열 타입

: 타입 [ ] 데이터 배열을 표현
문자열 배열임을 추론가능

문자형 +숫자형 혼합된 배열을 생성해서 오류가 남
any 타입 => 혼합 사용 가능

any는 아주 유연하지만 ts의 장점 타입 기능을 활용하지 못하게 할 수 있다!
다시 코드를 이렇게 바꿔서
for문으로 돌림
person의 hobbies를 반복한다.


hobby.toUpperCase()를 사용해도 문제가 없는 이유
=> ts는 이미 hobbies가 문자열의 배열 타입이라고 이해하고 있기 때문입니다.


그래서 map 메소드는 불가능! ( 배열은 사용이 가능하지만, 문자열에서는 사용 불가)
튜플 작업하기
Tuple [1, 2]
배열이지만, 길이와 타입이 고정된 배열입니다.
js에는 없습니다.

튜플은 항상 두 개의 요소만 지녀야 한다.
첫 번째 요소는 숫자 식별자 / 두번째 요소는 문자열 식별자 (설명)

문자열이나 숫자를 저장할 배열을 지정하면 ts가 이해할 수 있다는 의미
이는 유니온 타입입니다.
중요한 점 : ts는 이러한 유형의 값이 포함된 배열이어야 한다고 이해 함
단점: push 를 하면 오류없이 가능하다

ts는 role 이 문자열타입이나 숫자 배열이라는 것만 인지함
따라서 이 숫자를 두 번쨰 요소에 할당하고 author를 숫자로 대체하는 것이 허용됨
즉, 2개의 요소 중 첫번째 요소는 숫자 / 두번째 요소는 문자열이어야 한다는 것을
ts는 알지 못합니다.
그것을 재정의하고 알려줄 수 있는 튜플이 좋습니다.
튜플의 기능

role의 넘버 스트링 이 코드에는 딱 두개의 요소만 있는 특수 배열을 입력해야 한다.(role정의)
첫번째는 넘버 두번쨰는 스트링
딱 두개의 타입만 입력 가능
role 배열에 push admin이 가능한 이유는?

- push는 예외적으로 튜플에서 허용됨
- ts는 이런 에러를 걸러내지 못하지만, 적어도 잘못된 값을 할당하지 않는다.

추가 요소를 추가하면 에러 발생
열거형 Enum
enum { NEW, OLD }
사람이 읽을 수 있는 라벨
ID는 각각 관리자 0 / 읽기 전용 사용자 1 / 작성자 2 지정
이 숫자들로 정확히 동일하게 지정 가능
* 단점
- 역할이 없을 수도 있는 숫자를 추가해야 함 => role 추출 > if 검사 수행하면 에러 발생
- 개발자들은 2가 작성자인지 뭔지 기억못할 수 있다는 단점도 있다.
- 인간이 읽을 수 있는 식별자가 좋다. ex)ADMIN 이나 READ ONLY USER ...

role에 지정했던 것과 똑같이 if문에서 검사할수있어야 한다.
컴파일 실패 => 콘솔에 출력되지 않는다.
*문자열 식별자의 단점
js에서는 보통 전역 상수 설정
const ADMIN = 0;
const READ_ONLY =1;
const AUTHOR =2;
const person = {
name: 'sunam',
age: 30,
hobbies: ['Sports', 'Cooking'],
role : ADMIN
}
let favoriteActivites: string[];
favoriteActivites = ['Sports'];
console.log(person.name);
for(const hobby of person.hobbies){
console.log(hobby.toUpperCase());
}
if (person.role === ADMIN){
console.log('is read only');
}
JS의 이런 방식은 어디서나 사용할 수 있는게 장점

단점은 role 이 숫자로 추론됨

모든 상수를 정의하고 관리해야 한다
이 것을 enum으로 해결 가능!
enum 정의 방법

이 모든 작업을 라벨을 숫자로 할당하게 해주는 enum으로 수행했다
app.js에서 보면

컴파일된 코드에서 Role은 객체로 관리됨

개발자들에게는 이런식으로 생성된 숫자가 편리하다
만약 숫자가 0부터 시작되기 싫으면?

지정해준 숫자부터 +1 씩 자동부여됨
또는 다음 숫자나 문자를 다르게 하고싶으면..

각각 지정해줘도 가능합니다.

문자도 할당 가능!
- 위에서 정의한 다음 enum Role { ... }
- role 타입을 참조하거나 사용자 정의 타입을 참조하거나
- 타입 배정 사용하거나 if 에 사용하거나 좋다.
인간이 읽을 수 있고 백그라운드에서 매핑된 값이 있는 식별자가 필요할 때 훌륭한 구성
Any 타입
장점
- 가장 유연한 타입
- ts에게 어떤 것도 이해시키지 않는다.
- 모든 종류의 값을 저장 할 수 있다.
타입배정도 딱히 필요없다.
단점
- ts가 주는 모든 장점을 any가 상쇄시켜 바닐라 js를 쓰는것과 다를게 없다.
- ts 컴파일러가 작동하지 않게 되어 어떤 값이나 종류의 데이터가 어디에 저장될지 파악이 힘듬
- 단점 때문에 가능한 any를 쓰지 않게 될 것

런타임 도중 이처럼 특정 값에 수행하고자 하는 작업의 범위를 좁히기 위해 any를 사용하면 된다.
그 외에는 쓰지 않는게 좋습니다.
조합 타입
combine을 쓰면, n1 + n2 의 더하기 연산자로
숫자와 문자열을 모두 포함 시킬 수 있습니다.
숫자가 결과로 반환될 수도 있고, 문자열이 연결되어 반환 될 수도 있습니다.
function combine(input1: number, input2: number){
// js는 boolean 타입이 오면 알아서 참인지 아닌지를 검사한다.
let result = input1 + input2;
return result;
}
const combineAges = combine(30, 26);
console.log(combineAges);

제대로 작동되네요
그런데 문자열을 생성하려하면 문제가 생깁니다.

sunam 이라는 타입의 인수는 number 타입에 할당 불가능 하다.
이처럼 서로 다른 두 타입의 값을 사용해야 하는 어플리케이션에서는
유니언 타입을 사용합니다.

오류가 뜨네요

더하기 연산자는 '문자열이나 숫자' 타입에 적용 불가능하다는 err
=> ts는 유니언 타입만 이해할뿐 유니언 타입 내에 무엇이 있는지 분석 x
해결 방법
런타임 타입 검사 추가
ts는 input1과 input2가 둘다 숫자인경우와
그렇지 않을 경우는 문자열로 합하는 것을 반환하도록 했다.
function combine(input1: number | string, input2: number | string){
let result;
if(typeof input1 === 'number' && typeof input2 === 'number'){
result = input1 + input2;
} else {
result = input1.toString() + input2.toString();
}
return result;
}
const combineAges = combine(30, 26);
console.log(combineAges);
const combineNames = combine('sunam', 'love');
console.log(combineNames);

두 경우가 잘 나온다.
코드의 어느 위치에서든 함수 내에서 수행하는 작업과 관련하여 보다 유연하게 유니언 타입을 활용하는 방법
이 추가적인 런타임 타입 검사는 유니언 타입을 사용하여 작업할 때 종종 필요하다.
코드에 적용한 매개변수를 보다 유연히 사용가능
리터럴 타입 ( + 유니언타입)
단순한 특정 변수나 매개변수가 아님
숫자나 문자열도 아니며 정확한 값을 가지는 타입입니다.

타입이 추론되지않고, 2.8이라고 되어있습니다
변하지 않는 상수이기 때문
2.8은 숫자지만, 특정한 숫자임
문자열등에서도 유용하게 쓰일 수 있다.
function combine(
input1: number | string,
input2: number | string,
resultType: string
){
let result;
if(typeof input1 === 'number' && typeof input2 === 'number'){
result = input1 + input2;
} else {
result = input1.toString() + input2.toString();
}
// 'as-number'일 경우 결과값을 숫자형으로 +result
if (resultType === 'as-number'){
return +result;
} else {
return result.toString();
}
}
const combineAges = combine(30, 26, 'as-number');
console.log(combineAges);
const combineStringAges = combine('30', '26', 'as-number');
console.log(combineStringAges);
const combineNames = combine('sunam', 'love', 'as-text');
console.log(combineNames);

3026는 문자열의 조합 결과
왜? 해당 타입들은 문자열로 input1.toString() ~ 여기에 해당되기 때문입니다.

고쳐보자면

input값들이 숫자이거나 또는 'as-number'일때
input값들을 숫자형으로 더해라 // (+) 단항 더하기 연산자를 이용해 문자열을 숫자로 변환

같은 결과값이 나옵니다
유니언타입 + 리터럴 타입

리터럴 타입은 스트링이나 숫자 등과 같은 핵심 타입을 기반으로 합니다.
이 타입을 특정 목적으로 사용이 가능
아무 문자열이 아닌 이 두 문자열만 허용(이 두 값중 하나여야함) => 리터럴
리터럴 타입들을 유니온타입으로 지정
공식문서 정리했던 자료 : https://codingnewbie.tistory.com/103
유니언 타입
타입 구성 (Composing Types)
객체들을 조합하여 더 크고 복잡한 객체를 만드는 방법과 유사하게 TypeScript에 타입으로 이를 수행하는 도구가 있습니다. 여러가지 타입을 이용하여 새 타입을 작성하기 위해 일상적인 코드에서 가장 많이 사용되는 두 가지 코드로는 유니언(Union)과 제네릭(Generic)이 있습니다.
유니언 (Unions) |
유니언은 타입이 여러 타입 중 하나일 수 있음을 선언하는 방법입니다.
예를 들어, boolean 타입을 true 또는 false로 설명할 수 있습니다:

참고: MyBool위에 마우스를 올린다면, boolean으로 분류된 것을 볼 수 있습니다
- 구조적 타입 시스템의 프로퍼티며, 나중에 살펴보겠습니다.
유니언 타입이 가장 많이 사용된 사례 중 하나는 값이 다음과 같이 허용되는
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;
}
string 또는 string[ ] 배열을 받는 함수도 가능하군..
TypeScript는 코드가 시간에 따라 변수가 변경되는 방식을 이해하며, 이러한 검사를 사용해 타입을 골라낼 수 있습니다.
| Type | Predicate (단정하다) |
| string | typeof s === "string" |
| number | typeof n === "number" |
| boolean | typeof b === "boolean" |
| undefined | typeof undefined === "undefined" |
| function | typeof f === "function" |
| array | Array.isArray(a) |
예를 들어, typeof obj === "string"을 이용하여, string과 array를 구분할 수 있으며
TypeScript는 객체가 다른 코드 경로에 있음을 알게 됩니다.

if문으로 구분하고 있네요 typeof obj === "string"
타입 알리어스(별칭) / 사용자 정의 타입
유니언 타입으로 작업을 수행할 때 항상 유니언 타입을 반복하는 것은 번거롭다.
그를 위한 멋진 ts 기능으로 타입 알리어스(별칭)이 있다.
알리어스를 만들고

이를 통해 코드의 양 줄일 수 있고 Combinable을 사용 시 항상 동일한 타입이나 동일한 유형 설정을 참조 가능
타입 알리어스 및 객체 타입
타입 별칭을 사용하여 타입을 직접 “생성”할 수 있습니다.
유니온 타입을 저장하는 것만 가능한 것이 아닙니다. 복잡할 수 있는 객체 타입에도 별칭을 붙일 수 있습니다.
type User = { name: string; age: number };
const u1: User = { name: 'Max', age: 30 }; // this works!
User라는 타입은 name은 문자열 age는 숫자타입!
u1: User 타입
타입 별칭의 장점 => 불필요한 반복을 피하고 타입을 중심에서 관리할 수 있습니다.
예를 들어, 다음 코드를 아래와 같이 단순화할 수 있습니다.
단순화 이전!
function greet(user: { name: string; age: number }) {
console.log('Hi, I am ' + user.name);
}
function isOlder(user: { name: string; age: number }, checkAge: number) {
return checkAge > user.age;
}
단순화 후
type User = { name: string; age: number };
function greet(user: User) {
console.log('Hi, I am ' + user.name);
}
function isOlder(user: User, checkAge: number) {
return checkAge > user.age;
}
퀴즈





함수 반환 타입 및 "무효"


ts는 반환되는 값도 추론합니다 마지막에 있는 => : number
number타입이 반환될 것을 예측합니다.
이것을 지정하는 것도 가능

void 타입 => 반환할게 없을 때 쓰이는 타입
function add(n1: number, n2: number) : number {
return n1 + n2;
}
function printResult(num: number){
console.log('result : ' + num);
}
printResult(add(5,12));
콘솔에는 17이라고 제대로 나옵니다.
여기서 void 타입을 반환하고있다. 콘솔만 찍고있고 반환하는것이 없다.

여기서 헷갈리는 부분
undefined 는 ts에서는 타입!입니다.

A function whose declared type is neither 'void' nor 'any' must return a value.ts(2355)
함수가 undefined를 비롯해 아무것도 반환하지 않는다면, void 사용
void를 사용하는 것은 함수에 의도적으로 반환문이 없다는 것을 의미

undefined 는 실제 값을 반환하지 않을 때 사용할 수 있다.
=> 근데 이것은 드문 경우고

결론 : void를 반환문과 사용하는게 맞다고 합니다.
undefined를 생성해야 하는 함수가 실제로 확실히 있는 경우 기본적으로 void 사용
값을 반환하지 않는 함수 사용하는 경우 void 표준 사용
void를 명시적으로 지정할 수 있지만, ts는 이 코드를 추론할 수 있는 차이가 있다.
타입의 기능을 하는 함수
function add(n1: number, n2: number) : number {
return n1 + n2;
}
function printResult(num: number) : void{
console.log('result : ' + num);
return;
}
printResult(add(5,12));
let combineValues;
combineValues = add;
console.log(combineValues(8, 8));

함수를 변수에 저장해놓고 콘솔에 찍으면



any기 때문에 컴파일이 가능하다.
ts는 원하지 않지만, 이해하지 못하는 부분여서 컴파일에 문제는 없다.
하지만, 런타임 오류가 뜬다.

이런 에러 방지는 combineValues가 함수를 가지고 있다고 명시하면 된다.
타입을 함수로 설정

함수를 저장하면


잘못된 함수 저장으로 원하는 결과가 나오지 않음
ts는 이런 문제에대해 알려줄 수 없다.
함수 타입은 함수의 매개변수와 반환값에 관련된 함수를 설명하는 함수로
js에서 이 화살표 함수 표기법에 따라 혹은 이 표기법에 가깝게 만들어짐

이 변수가 함수를 취하거나 두 숫자를 취하는 함수를 저장하고 number를 반환하도록

함수 타입 및 콜백(callback)
function addAndHandle(n1:number, n2:number, cb : (num : number) => void ){
const result = n1 + n2;
cb(result);
}
addAndHandle( 10, 20, (result) => {
console.log(result);
})

result = 10 + 20
콜벡의 이점
함수 내에 callback을 전달하면 ts 는 해당 결과가 number가 될것이라고 추론할 수 있다
그리고 void를 반환하고, 호출문에서 return을 쓰면?

결과적으로 오류는 없지만, cb가 여기서 반환되는 값으로 아무 작업도 할 수 없다고 cb 타입에 명확하게 정의되어 있다.
퀴즈



알수 없는, unknown 타입

unknown 타입
에러 발생없이 어떤 값이든 저장 할 수 있다 => 모든 것이 허용

unknown 이기 때문에 어떤 값이든 userInput으로 전달 될 수 있다.
any로 바꾸면 에러가 사라짐 => 유연한 타입 ( 타입 확인 수행 x )
사용하는 경우
userinput에 현재 저장된 타입을 확인해야 함

string 타입은 알수없는 타입에 할당할 수 없다.

할당하고 싶으면? 추가 검사 필요
고정된 값에 할당 할 수 있어 any보다 나은 점도 있다. ( 타입 검사 )
자주 사용하는 타입은 아니지만 특정 경우에 따라 나을 수 있습니다.
절대 타입 never
void와 다르게 반환 값이 있다.
타입스크립트에서 never 타입은 값의 공집합이다.
사실 또 다른 인기 자바스크립트 타입 시스템인 Flow에서 never 타입은 empty 타입과 같다.
집합에 어떤 값도 없기 때문에, never 타입은 any 타입의 값을 포함해 어떤 값도 가질 수 없다.
그래서 never 타입은 때때로 점유할 수 없는 또는 바닥 타입이라고 불린다.
function generateError(message: string, code: number){
throw {message: message, errorCode: code};
}
generateError('An error occurred!!', 500);

이 함수는 never를 반환, 반환값을 생성하지 않는다.

never 타입을 많이 사용하지 않을 수 있지만,
허용할 수 없는 함수 매개변수에 제한을 가한다.
'SeSAC 풀스택 > 타입스크립트' 카테고리의 다른 글
| 2023-03-17 [udemy] typeScript 강의 섹션1: 시작하기 (0) | 2023.03.17 |
|---|---|
| 2023-03-06 타입스크립트 / 함수 / (0) | 2023.03.06 |
| 2023-03-06 타입스크립트 2일차 / 인터페이스 / (0) | 2023.03.06 |
| 2023-03-06 타입스크립트 2일차 / 기본 타입 / (0) | 2023.03.06 |
| 2023-03-06 타입스크립트 2일차 타입스크립트의 목적/ ts for js programmers (0) | 2023.03.06 |