📔 201930324 이현종
|
이현종 |
🔋 마지막 주차 🔋 2023.11.29
🔋 2023.11.22
🔋 2023.11.15
🔋 2023.11.08
💭 설치
-
npx create-react-app my-app --template typescript -
npm install @types/react @types/react-dom
💭 TypeScript with React Components
-
React로 타입스크립트를 작성하는 것은 자바스크립트를 작성하는 것과 비슷합니다.
-
컴포넌트로 작업할 때 가장 큰 차이점은 컴포넌트의 props에 타입을 제공할 수 있다는 점입니다.
interface MyButtonProps {
title: string;
disabled: boolean;
}
function MyButton({ title, disabled }: MyButtonProps) {
return <button disabled={disabled}>{title}</button>;
}
export default function MyApp() {
return (
<div>
<h1>환영합니다.</h1>
<MyButton title="버튼" disabled={true} />
</div>
);
}🔋 2023.11.01
💭 일반적인 Generic Type 사용
function identity<Type>(arg: Type): Type {
return arg;
}
let myIdentity = identity;
const data = myIdentity("dealim");💭 예제
const users = [
{ id: 1, name: '홍길동' },
{ id: 2, name: '김선달' }
];
const products = [
{ id: 'a', title: '셔츠' },
{ id: 'b', title: '모자' }
];
function getUser(id) {
return users.find(user => user.id === id);
}
function getProduct(id) {
return products.find(product => product.id === id);
}
function addUser(user) {
users.push(user);
}
function addProduct(product) {
products.push(product);
}💭 리팩토링
interface User {
id: number;
name: string;
}
interface Product {
id: string;
title: string;
}
const users: User[] = [
{ id: 1, name: '홍길동' },
{ id: 2, name: '김선달' }
];
const products: Product[] = [
{ id: 'a', title: '셔츠' },
{ id: 'b', title: '모자' }
];
function getUser(id: number): User | undefined {
return users.find(user => user.id === id);
}
function getProduct(id: string): Product | undefined {
return products.find(product => product.id === id);
}
function addUser(user: User): void {
users.push(user);
}
function addProduct(product: Product): void {
products.push(product);
}💭 generic 사용
interface User {
id: number;
name: string;
}
interface Product {
id: string;
title: string;
}
const users: User[] = [
{ id: 1, name: '홍길동' },
{ id: 2, name: '김선달' }
];
const products: Product[] = [
{ id: 'a', title: '셔츠' },
{ id: 'b', title: '모자' }
];
interface Identifiable {
id: string|number;
}
function getEntity<T extends Identifiable>(id: Identifiable, entities: T[]): T | undefined {
return entities.find(entity => entity.id === id);
}
function addEntity<T extends Identifiable>(entity: T, entities: T[]): void {
entities.push(entity);
}
const retrievedUser = getEntity(1, users);
const retrievedProduct = getEntity('a', products);
addEntity({ id: 3, name: 'Charlie' }, users);
addEntity({ id: 'c', title: 'Shoes' }, products);🔋 2023.10.25
💭 null and undefined
타입스크립트에서도 위의 두 값을 의미하는 타입이 존재하며 이 타입들이 동작하는 방식은strictNullChecks옵션의 사용 여부에 따라 달라집니다.
💭 strictNullChecks off
strictNullChecks를 끄면null이거나undefined값에 정상적으로 액세스할 수 있으며,null및undefined은 모든 유형의 프로퍼티에 할당할 수 있습니다.
function greet(name?: string) {
// 'name'은 string 또는 undefined 일 수 있습니다.
return "Hello, " + name.toUpperCase();
}💭 strictNullChecks on
strictNullChecks를 켜면 값이null이거나undefined인 경우 해당 값에 메서드나 속성에 접근하기 전에 값을 테스트해야 합니다.
function greet(name?: string) {
// 'name'은 string 또는 undefined 일 수 있습니다.
return "Hello, " + name.toUpperCase();
}💭 on-null Assertion Operator (Postfix !)
-
타입스크립트에는 직접적인 체크 없이 타입에서null과undefined을 제거하는 특별한 구문도 있습니다. -
표현식 뒤에
!을 사용하면 사실상 값이null과undefined이 아니라는 것을 의미합니다.
function liveDangerously(x?: number | null) {
// No error
console.log(x!.toFixed());
}💭 Generic Type
-
C# 및 Java와 같은 언어에서재사용 가능한 컴포넌트를 만들기 위한 기능 중 하나는generics입니다. -
이는
단일 타입이 아닌다양한 타입에서 작동할 수 있는컴포넌트를 만들 수 있는 기능입니다.
function identity(arg: string|number): string|number {
return arg;
}
let id = identity("dealim"); //let id: string | numberfunction identity<Type>(arg: Type): Type {
return arg;
}
let id = identity<string>("dealim"); //let id: string
let id2 = identity<number>(52); //let id: number
let id3 = identity<boolean>(true); //let id: boolean
let nid = identity("dealim"); //let id: string
let nid2 = identity(52); //let id: number
let nid3 = identity(true); //let id: boolean- 해당 함수를 호출할때는 두가지 방법으로 호출이 가능합니다.
- 인수 호출 전 <> 안에 캡쳐할 타입을 명시적으로 선언하기
- 평소대로 호출하고 인수값을 바탕으로 typescript가 타입을 추론하도록 하기
-
수요일 오전 10시 ~ 10시50분
-
객관식 + 주관식 문제
-
주관식 : 예제코드 빈칸 채우기, 코드 해석 1문제(동작 로직) -> 어떤걸 인수로 받는지 등등..
-
리펙토링 : 코딩 컨벤션, 백틱, 템플릿 스트링, 디스트럭처링
-
문항: 20문제
- 🔥 7주차
- 문제 1번
-
실습1에서 CRUD 함수를 추가해보세요.
-
addStudent(student) -> student를 data에 추가
-
updateStudent(student) -> student 객체 안의 id를 기반으로 data 업데이트
-
seletctStudent(id) -> 해당 id를 가진 student 리턴
-
deleteStudent(id) -> 해당 id를 가진 student 삭제
-
🔥 6주차
- 문제 1번
-
위 링크의 데이터 구조를 파악하고 type을 정의해보세요.
-
type, interface 사용
-
리터럴 타입 사용
-
eslint 체크
- 문제 2번
-
위 링크의 데이터를 바탕으로 타입을 정의해보세요.
-
type, interface 사용
-
리터럴 타입 사용
-
eslint 확인
-
🔥 5주차
- 문제 1번
- Type Aliases 를 사용하여 위의 코드를 리펙토링해 보세요.
- Interfaces를 사용하여 위의 코드를 리펙토링해 보세요.
- 문제 2번
- 실습1에서 만든 코드에서 추가로 printAdminUserInfo 함수 구현
- 해당 함수에서는 기존의 User정보에 role이라는 컬럼을 추가해서 출력
- 기존의 Interface, type을 확장
-
위 링크에서 포함된 데이터 세트에 대한 타입과 인터페이스를 지정하세요.
-
그리고 강아지 또는 고양이만 console로 출력하는 함수를 만들어 보세요.
-
printData("dog")
-
printData("cat")
-
지금까지 배운 내용을 바탕으로 지난시간에 진행했던 실습을 리펙토링 해 보세요.
-
type 또는 interface 사용
-
literal types 적용
-
🔥 4주차
const data = [{
"id": "p1",
"name": "사과",
"price": 1500,
"stock": 10,
"category": "식품",
"discount": "10%"
},
{
"id": "p2",
"name": "노트북",
"price": 1500000,
"stock": 5,
"category": "전자제품",
"spec": "i7, 16GB RAM"
},
{
"id": "p3",
"name": "티셔츠",
"price": 20000,
"stock": 20,
"category": "의류",
"size": "M"
},
{
"id": "p4",
"name": "식빵",
"price": 2500,
"stock": 30,
"category": "식품",
"discount": 500
},
{
"id": "p5",
"name": "휴대폰",
"price": 1000000,
"stock": 10,
"category": "전자제품",
"discount": "5%"
}]- 🔥 3주차
- 위 함수의 문제점을 찾아보세요. 위 함수가 문제가 발생하는 케이스를 작성하고 해결하기 위해서 어떻게 해야할지 코드를 수정해보세요.
function calculateAverage(scores: number[]) {
let total = 0;
let count = 0;
for (const score of scores) {
if (score) {
total += score;
count++;
}
}
return total / count;
}- 위 코드에서
function printBoard(result: any) {
console.log(result)
}- 이 부분만 수정해서 아래와 같이 출력되도록 수정해보세요. 그리고 result: any 부분을 아래의 출력에 필요한 데이터만 받도록 처리하고 type 선언을 해주세요.
function printBoard(result: any) {
console.log(result)
}
fetch('https://static-contents-serve.s3.ap-northeast-2.amazonaws.com/response.json').then((result)=>{
return result.json()
}).then(list => {
list.forEach((data: any)=>{
printBoard(data)
})
}).catch(err => {
console.log(err)
});🔋 2023.10.04
- typescript에서는
string이나number와 같은 타입 뿐만 아니라 값 자체를 의미하는리터럴 타입도 정의할 수 있습니다. 이러한리터럴 타입을정의하는 방법과 함께타입스크립트가javascript에서 변수를 선언하는 방식에 따른 동작을 이해할 필요가 있습니다.
let changingString = "Hello World";
changingString = "안녕하세요.";
// 위에서 changingString은 가능한 모든 스트링을 나타낼 수 있기 때문에
// 타입스크립트에서는 아래와 같이 인식합니다.
changingString; // let changingString: string
const constString = "Hello World";
// constString은 오로지 "Hello World"라는 문자열만을 의미합니다.
// 타입스크립트에서는 아래와 같이 인식합니다.
constString; // const constString: "Hello World"let x: "hello" = "hello";
x = "hello"; // 정상동작
x = "howdy"; // 에러
Type '"howdy"' is not assignable to type '"hello"'.Type '"howdy"' is not assignable to type '"hello"'.function printText(s: string, alignment: "left" | "right" | "center") {
// ...
}
printText("안녕하세요.", "left");
printText("반갑습니다.", "centre");
Argument of type '"centre"' is not assignable to parameter of type '"left" | "right" | "center"'.Argument of type '"centre"' is not assignable to parameter of type '"left" | "right" | "center"'.function compare(a: string, b: string): -1 | 0 | 1 {
return a === b ? 0 : a > b ? 1 : -1;
}interface Options {
width: number;
}
function configure(x: Options | "auto") {
// ...
}
configure({ width: 100 });
configure("auto");
configure("automatic");
Argument of type '"automatic"' is not assignable to parameter of type 'Options | "auto"'.Argument of type '"automatic"' is not assignable to parameter of type 'Options | "auto"'.const obj = { counter: 0 };
obj.counter = 1;TypeScript는 이전에 0이었던 필드에 1을 할당하는 것을 오류라고 가정하지 않습니다. (const임에도 불구하고) 다르게 말하면, obj.counter에는 0이 아닌 타입인 number로 추론합니다.
declare function handleRequest(url: string, method: "GET" | "POST"): void;
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"'.Argument of type 'string' is not assignable to parameter of type '"GET" | "POST"'.Try-
위의 예제에서 req.method는 "GET"이 아닌 string으로 추론됩니다. req를 생성하고 handleRequest를 호출하는 사이에 “안녕하세요"와 같은 다른 문자열을 req.method에 할당할 수 있기 때문에 TypeScript는 이 코드에 오류가 있는 것으로 간주합니다.
-
이 문제를 해결하기 위해 두가지 방법을 사용 할 수 있습니다.
- 둘중 하나의 위치에 as를 통해 명시적으로 타입을 지정하는 방법이 있습니다.
// Change 1:
const req = { url: "https://example.com", method: "GET" as "GET" };
// Change 2
handleRequest(req.url, req.method as "GET");-
Change 1은 "req.method가 항상리터럴 타입"GET"을 갖도록 하여 이후 해당 필드에 "안녕하세요"와 같은 다른 문자열을 할당할 수 없도록 하겠습니다."를 의미합니다. -
Change 2는 "req.method가 "GET" 값을 갖습니다."를 의미합니다.
as const를 이용하여req 객체자체를type literals로 고정합니다.
const req = { url: "https://example.com", method: "GET" } as const;
handleRequest(req.url, req.method);🔋 2023.09.27
type alias는 타입에 대한 이름을 지정하여 재 사용 가능하도록 하는 구문입니다.
type Point = {
x: number;
y: number;
};
function printCoord(pt: Point) {
console.log("The coordinate's x value is " + pt.x);
console.log("The coordinate's y value is " + pt.y);
}
printCoord({ x: 100, y: 100 });-
객체 타입은 위와 같이 type을 선언하여 사용 할 수 있습니다. -
printCoord의 파라미터 값에 타입 어노테이션을 이용해 pt에 대한 타입을 지정했던 방식과는 달리 상단에 type alias를 선언해서 pt에 지정해주는 방식을 사용함으로 써 Point라는 타입을 재사용 할 수 있도록 처리했습니다. -
유니온 타입의 경우도 아래와 같이 사용 가능합니다.
type ID = number | string;- 인터페이스는 type의 이름을 지정하는 또 다른 방법입니다.
interface Point {
x: number;
y: number;
}
function printCoord(pt: Point) {
console.log("The coordinate's x value is " + pt.x);
console.log("The coordinate's y value is " + pt.y);
}
printCoord({ x: 100, y: 100 });// 1. 병합
interface User {
name: string;
}
interface User {
age: number;
}
const userInfo: User = { name: "철수", age: 22 }; // No error
type UserType = { // Error: Duplicate identifier 'UserType'.
name: string;
};
type UserType = { // Error: Duplicate identifier 'UserType'.
age: number;
};
// 2. 확장
interface Animal {
sound: string;
}
interface Dog extends Animal {
breed: string;
}
class MyDog implements Dog {
sound = "멍멍";
breed = "진돗개";
}
const dog: Dog = {
sound: "왈왈",
breed: "치와와"
}
type AnimalType = {
sound: string;
};
type DogType = AnimalType & {
breed: string;
};
// 3. Union, Intersection (확장)
// interface Button = PrimaryButton | SecondaryButton; // Error
type PrimaryButton = { label: string, primary: true };
type SecondaryButton = { label: string, primary: false };
type ButtonType = PrimaryButton | SecondaryButton;
// 4. 처리 가능한 속성
// interface ComputedProps { // Error
// [key: `prop_${string}`]: string;
// }
type ComputedPropsType = {
[key: `sound_${count}`]: string;
};interface User {
id: string;
name: string;
}
type ID = string | number;
type AnimalOrID = Animal | ID;🔋 2023.09.20
type alias는 타입에 대한 이름을 지정하여 재 사용 가능하도록 하는 구문입니다.
type Point = {
x: number;
y: number;
};
function printCoord(pt: Point) {
console.log("The coordinate's x value is " + pt.x);
console.log("The coordinate's y value is " + pt.y);
}
printCoord({ x: 100, y: 100 });-
객체 타입은 위와 같이 type을 선언하여 사용 할 수 있습니다. -
printCoord의 파라미터 값에 타입 어노테이션을 이용해 pt에 대한 타입을 지정했던 방식과는 달리 상단에 type alias를 선언해서 pt에 지정해주는 방식을 사용함으로 써 Point라는 타입을 재사용 할 수 있도록 처리했습니다. -
유니온 타입의 경우도 아래와 같이 사용 가능합니다.
type ID = number | string;- 인터페이스는 type의 이름을 지정하는 또 다른 방법입니다.
const data = [{
"id": "p1",
"name": "사과",
"price": 1500,
"stock": 10,
"category": "식품",
"discount": "10%"
},
{
"id": "p2",
"name": "노트북",
"price": 1500000,
"stock": 5,
"category": "전자제품",
"spec": "i7, 16GB RAM"
},
{
"id": "p3",
"name": "티셔츠",
"price": 20000,
"stock": 20,
"category": "의류",
"size": "M"
},
{
"id": "p4",
"name": "식빵",
"price": 2500,
"stock": 30,
"category": "식품",
"discount": 500
},
{
"id": "p5",
"name": "휴대폰",
"price": 1000000,
"stock": 10,
"category": "전자제품",
"discount": "5%"
}]
function printProductInfo(product: {
id: string;
name: string;
price: number;
stock: number;
category: string;
discount?: string | number;
spec?: string;
size?: string;
}) {
const { id, name, price, stock, category, discount, spec, size } = product;
let discountedPrice;
if (typeof discount === 'string') {
const discountPercentage = parseInt(discount, 10);
discountedPrice = price - (price * discountPercentage / 100);
} else if (typeof discount === 'number') {
discountedPrice = price - discount;
} else {
discountedPrice = price;
}
const TotalPrice = price.toLocaleString();
const TotalDiscountedPrice = discountedPrice.toLocaleString();
let result = `ID: ${id}, 이름: ${name}, 가격: ${TotalPrice}원, 할인가: ${TotalDiscountedPrice}원, 재고: ${stock}, 카테고리: ${category}`;
if (spec !== undefined) {
result += `, 스펙: ${spec}`;
}
if (size !== undefined) {
result += `, 사이즈: ${size}`;
}
return result;
}
for (const product of data) {
const productInfo = printProductInfo(product);
console.log(productInfo);
}🔋 2023.09.13
- 객체 타입을 타입스크립트에서 정의하는 법
function printUserName(name: string){
console.log(name)
}
function printCoordinate(pt: {x: number, y: number}){
console.log(`x 좌표 ${pt.x}`);
console.log(`y 좌표 ${pt.y}`);
}
printCoordinate({ x: 3, y: 7 });-
함수 파라미터에 두개의 속성이 있는 타입을
number로 정의했습니다. -
명시적으로 타입을 지정하지 않을 경우
any타입으로 지정됩니다. -
이때,
noImplicitAny설정이 되어있다면 에러가 발생하고,any타입으로 가정하여 에러가 발생하지않습니다.
-
객체 타입을 지정할 때 경우에 따라 일부 속성값은 들어갈 수도 있고, 들어가지 않을 수도 있는 선택사항일수도 있습니다.
-
그럴 경우에는 해당 속성 값의 바로 뒤에
?를 넣어서 표현
function printUser(obj: { name: string, age?: number }, ) {
if(!obj) console.log(`아무런 정보가 없습니다.`);
else{
console.log(`Name: ${obj.name}`);
if (obj.age) console.log(`Age: ${obj.age}`);
}
}
printUser();
printUser({name: "홍길동"});
printUser({name: "김길동", age: 21});- Optional Chaining은 객체의 속성이나 배열의 요소, 함수의 리턴값이
null또는undefined일 경우에 안전하게 접근할 수 있게 해주는 JavaScript 문법입니다.
function printCity(obj: { name: string; address?: { city: string }}) {
console.log(`Name: ${obj.name}`);
if( obj.address & obj.address.city) {
console.log(`City: ${obj.address.city}`);
}
}
printCity({ name: "홍길동" });
printCity({ name: "김길동", address: { city: "서울" } });function printCityO(obj: { name: string; address?: { city: string }}) {
console.log(`Name: ${obj.name}`);
// address에 city값이 있을 경우 진행하고 없을 경우 "알수없음" 출력
console.log(`City: ${obj.address?.city || "알수없음"}`);
}
printCity({ name: "홍길동" });
printCity({ name: "김길동", address: { city: "서울" } });- Temary Operator는
조건 ? 참일때 리턴 : 거짓일때 리턴형식으로 if문을 대신하여 사용할 수 있는 연산자입니다.
function printUser(obj: { name: string; age?: number }){
console.log(`Name: ${obj.age}`);
if(obj.age) {
console.log(`Age: ${obj.age}`);
}else{
console.log("Age: UnKnown");
}
// const result = obj.age ? obj.age : 'Unknown';
// console.log(result)
}
printCity({ name: "홍길동" });
printCity({ name: "김길동", age: 21 });function printUser(obj: { name: string; age?: number }) {
console.log(`Name: ${obj.name}`);
console.log(`Age: ${obj.age ? obj.age : 'Unknown'}`);
}
printUser({ name: "홍길동" }); // Output: "Name: 홍길동", "Age: Unknown"
printUser({ name: "김길동", age: 21 }); // Output: "Name: 김길동", "Age: 21"-
타입을 결합하는 방법중 하나는 union type입니다. union type은 두개 이상의 다른 타입으로 구성된 타입으로 해당 타입중 하나가 될 수 있는 것을 의미합니다. 이러한 타입들을 유니온의 각 member라고 합니다.
-
string 또는 number가 될 수 있는 타입을 선언할 수 있습니다.
function printId(id: number | string) {
console.log(`당신의 ID: ${id}`);
}
printId(101);
printId("202");
printId({ myID: 22342 });function printId(id: number | string) {
console.log(`당신의 ID: ${id.toUpperCase()}`);
}
printId("202");-
타입스크립트에서
string | number로 유니온 타입을 사용 할 경우 해당 함수 내부에서는 두 타입 모두가 허용하는 속성과 메서드만 사용 할 수 있습니다. -
이런 상황에서의 해결책은 javascript 코드를 기반으로 타입스크립트가 해당 타입을 ‘추론’ 할 수 있도록 명시적으로 처리하는 것입니다.
function printId(id: number | string) {
if (typeof id === "string") {
console.log(`당신의 ID: ${id.toUpperCase()}`);
} else {
console.log(id)
}
}
printId("202");-
&&연산자는 두 피연산자가 모두 true일 경우 true를 반환합니다. 첫 번째 피연산자가 false이면 두 번째 피연산자는 체크하지 않습니다. (short-circuit evaluation - 단축평가계산) -
좀 더 정확하게 표현하면 첫번째 피연산자가
Falsy이면 첫번째 피연산자 값을 리턴하고 모두Truthy면 마지막 피연산자 값을 리턴합니다. -
||연산자는 두 피연산자 중 하나라도 true일 경우 true를 반환합니다. 첫 번째 피연산자가 true이면 마찬가지로 두 번째 피연산자는 평가되지 않습니다. -
여기도 좀 더 정확하게 표현하면 첫번째 피연산자가 Truthy면 첫번째 피연산자를 리턴하고 둘 다 Falsy면 마지막 피연산자를 리턴합니다.
let isAccountActive = true;
let isEmailVerified = true;
if (isAccountActive && isEmailVerified) {
console.log("로그인 성공!");
} else {
console.log("로그인 실패!");
}
if (!isAccountActive || !isEmailVerified) {
console.log("로그인 실패!");
} else {
console.log("로그인 성공!");
}let isConnected = false;
function fetchData() {
console.log('데이터를 가져옵니다.');
return true
}
if (isConnected && fetchData()) {
console.log('데이터 조회 성공');
}let age = 25;
let isAdult = (age >= 18) && "해당 사용자는 성인입니다.";
console.log(isAdult);
age = 15;
let message = (age >= 18) || "해당 사용자는 성인이 아닙니다.";
console.log(message);-
JavaScript에서"truthy"와"falsy"는 논리 연산자의 피연산자가 true 또는 false로 간주되는 경우를 설명하는 용어입니다. 이 차이를 이해하지 않고 각종 조건문을 사용하면 코드가 의도한대로 동작하지 않는 상황을 마주할 수 있습니다. -
Javascript에서 아래의 조건절들은 모두truthy로 취급됩니다.
if (true)
if ({})
if ([])
if (42)
if ("0")
if ("false")
if (new Date())
if (-42)
if (12n)
if (3.14)
if (-3.14)
if (Infinity)
if (-Infinity)- 정리하면 아래와 같은 값들이
truthy입니다.
**true`**- 모든 숫자 (0을 뺀)
- 모든 문자열 (**
'',“”**을 제외) - 모든 객체와 배열 (빈 객체와 빈 배열 포함)
Javascript의 이러한 특징 때문에 아래와 같은 코드는 문제를 발생 시킬 수 있습니다.
const score = 0;
if (score) {
console.log(`현재 스코어: ${score}`);
} else {
console.log('서버로부터 스코어 값을 받아오지 못했습니다');
}- 위 코드의 경우 다양하게 해석 될 수 있지만 의도는 아래와 같다고 가정하겠습니다.
score값을 서버로부터 받아옴score값 자체가 비어있을 수 있기에if (score)를 통해 예외처리- 현재 서버로부터
score의 값을 받아왔고 해당 값은0
- 따라서 위 코드의 결과는
현재 스코어: 0이 출력되어야 합니다.
function welcomePeople(x: string[] | string) {
if (Array.isArray(x) && x.length > 0) {
console.log(`${x[0]}님 외 ${x.length}명의 방문을 환영합니다.`);
} else {
console.log(`${x}님 환영합니다.`);
}
}-
Array.isArray메서드를 이용해 array타입인지 체크하고 각각의 케이스에 맞는 동작 코드를 수행하도록 처리되어 있습니다. 해당 코드에 따라 타입스크립트는 welcaomePeople에서 사용되는 유니온 타입들중 현재 x값이 array인지 string인지 체크 할 수 있습니다. 따라서 오류가 발생하지 않습니다. -
유니온 타입의 모든 맴버가 공통적으로 가지고 있는 메서드를 호출할 때 역시 별도의 오류 메세지를 발생시키지 않습니다. 대표적으로 slice 메서드는 string과 array 모두 가지고 있는 메서드입니다. 따라서 아래의 코드는 오류를 발생시키지 않습니다.
function getFirstThree(x: number[] | string) {
return x.slice(0, 3);
}
console.log(getFirstThree("안녕하세요"));
console.log(getFirstThree([1,2,3,4,5,6,7,8]));- 위 함수의 문제점을 찾아보세요. 위 함수가 문제가 발생하는 케이스를 작성하고 해결하기 위해서 어떻게 해야할지 코드를 수정해보세요. 타입스크립트 플레이그라운드(https://www.typescriptlang.org/play) 에서 코드를 작성하고 주석을 이용해 수정한 내용과 설명을 작성해주세요. 코드 링크 (Export -> Copy as Markdown Link)와 코드 화면을 캡쳐해서 첨부 후 제출하세요.
function calculateAverage(scores: number[]) {
let total = 0;
let count = 0;
for (const score of scores) {
if (score) {
total += score;
count++;
}
}
return total / count;
}- 답안
function calculateAverage(scores: number[]) {
let total = 0;
const count = scores.length;
for (const score of scores) {
total += score;
count++;
}
return count === 0 ? '입력값X' : total / count;
}
console.log(calculateAverage([10, 20, 30, 0, 50, 60]));- 답안
function printBoard(result: {
RNUM_DESC: string;
CATEGORY_NM: string;
WRITE_DATE: string;
HITS: number;
FILE_CNT: number;
}) {
const { RNUM_DESC, CATEGORY_NM, WRITE_DATE, HITS, FILE_CNT } = result;
console.log(`${RNUM_DESC} - ${CATEGORY_NM} - ${WRITE_DATE} - 조회 ${HITS} - 첨부파일수 ${FILE_CNT}`)
}
fetch('https://static-contents-serve.s3.ap-northeast-2.amazonaws.com/response.json').then((result)=>{
return result.json()
}).then(list => {
list.forEach((data: any)=>{
printBoard(data)
})
}).catch(err => {
console.log(err)
});🔋 2023.09.06
- 자바스크립트에서 주로 사용되는 원시 타입인
string,number,boolean은 타입스크립트에서 대응하는 타입이 있습니다. string은 "Hello World"와 같은 문자열 값을 나타냅니다.number는 42와 같은 숫자를 나타냅니다. 자바스크립트에는 정수에 대한 특별한 런타임 값이 없으므로 int나 float에 해당하는 값을 없으며 모든 것이 숫자입니다.boolean은true,false두 값에 사용됩니다.- 원시 타입의 이름을 지정할때 String, Number와 같이 대문자로 시작하면 안됩니다.
- 불변성
- 메모리 효율성
- 비교 시 값 자체를 비교 (Call by value)
- 가변성
- 객체로서 추가 메서드 및 프로퍼티를 가질 수 없음
- 비교 시 참조를 비교 (Call by reference)
- 배열에 타입을 지정할 때는 그 배열을 구성하는 타입과 [] 표기를 사용합니다.
- TypeScript의 any타입은 변수가 어떤 타입이든 될 수 있음을 나타냅니다. 일종의 프리패스권 또는 타입체크를 회피 하는 용도로 사용되다 보니 타입스크립트에 익숙하지 않은 개발자가 개발하는 과정에서 무분별하게 많이 쓰이게 되는 타입중 하나입니다.
- 이름 그대로 모든 것을 허용하는 타입입니다.
- 자바스크립트 프로젝트를 타입스크립트로 마이그레이션하는 과정이 아닌 한, 기본적으로 사용하지 않는 것을 권장
- 해당 라인이 문제가 없을것이라는 것을 확신 할수 있을 때
- 타입정보가 없거나 미흡한 외부 라이브러리 등을 사용할 때
- 실행시점에 타입이 결정되어서 타입을 미리 정할 수 없을 때
- 기본적으로 타입스크립트에서 타입이 지정되어 있지 않은 변수들에 대해
문맥상 타입을 추정할수 없다면 컴파일러에서는any타입으로 가정합니다.
- 타입스크립트는 일반적인 언어에서 사용하는 int x = 0; 와 같은 “왼쪽에 타입을 정의하는” 스타일을 사용하지 않습니다. 타입 어노테이션은 항상 작성한 내용 다음에 오게 됩니다.
- Parameter Type Annotations
-
함수를 선언할 때 각 매개변수 뒤에 타입 어노테이션을 추가하여 함수가 허용하는 매개변수 타입을 선언할 수 있습니다.
-
매개변수에 타입 어노테이션이 지정되면 해당 함수를 호출 할 때 인자값을 체크하게 됩니다.
-
템플릿 스트링은 ES6에서 도입된 자바스크립트의 문자열 처리 방식중 하나입니다. 이 방식은 기존의 문자열을 다루기 위한 작은따옴표(‘’ ), 큰따옴표(“”) 대신 백틱(``) 이라는 문자를 사용하여 표현됩니다.
-
이를 사용하면 두가지 장점을 가져갈 수 있습니다.
-
멀티라인 문자열: 백틱을 사용하면 문자열을 여러 줄에 걸쳐 쓸 수 있습니다.
-
문자열 삽입: ${}를 사용하여 문자열 안에 변수나 식을 삽입할 수 있습니다.
- Promises를 리턴하는 함수에 타입 어노테이션을 달고 싶다면 Promise 타입을 사용해야 합니다.
-
Promise는 비동기 작업의 최종 완료 또는 실패를 나타내는 객체입니다. 주로 서버와의 비동기 통신, 파일 읽기 등에 사용됩니다.
-
비동기 작업 - 일반적으로 Javascript는 코드를 실행할때 위에서부터 아래의 순서대로 실행되게 됩니다.
- 익명 함수(또는 arrow function)의 경우도 비슷한 방식으로 타입 어노테이션을 달 수 있습니다.
-
익명 함수(Anonymous Function)는 이름이 없는 함수를 의미합니다. 이러한 함수는 주로 함수의 인자로 전달되거나, 변수에 할당되어 사용됩니다.
-
기본 문법 - JavaScript 및 TypeScript에서 익명 함수를 만드는 가장 기본적인 방법은 다음과 같습니다
-
콜백 함수로 사용 - 익명 함수는 콜백 함수로도 많이 사용됩니다. 예를 들어, 배열의 map 메소드에 익명 함수를 전달할 수 있습니다
-
화살표 함수 - ES6(ES2015) 이후, 화살표 함수(arrow function)라는 더 간단한 문법으로 익명 함수를 만들 수 있습니다
-
즉시 실행 함수(IIFE) - 익명 함수는 즉시 실행되도록 할 수도 있습니다. 이를 즉시 실행 함수 표현식(IIFE, Immediately Invoked Function Expression)이라고 합니다.
-
익명 함수는 함수의 이름을 명시하지 않기 때문에 디버깅이 어렵거나, 재귀 호출 같이 함수가 자기 자신을 호출해야 하는 상황에서는 사용이 제한될 수 있습니다. 그러나 간단한 로직을 변수에 할당하거나, 콜백으로 전달해야 하는 경우에는 코드를 간결하게 만들어 주는 장점이 있습니다.
🔋 2023.08.30
-
💻오리엔테이션
-
📃타입스크립트 개요
- TypeScript는 Microsoft에서 개발한 자바스크립트의 확장 버전으로, 정적 타입 검사와 클래스 기반 객체 지향 프로그래밍을 추가한 언어입니다.
- TypeScript는 큰 규모의 애플리케이션 개발에 적합하며, 오류를 줄이고 가독성과 유지보수성을 향상시키는데 도움을 줍니다.
- 📜JavaScript와 TypeScript의 차이점
- JavaScript는 동적 타입 언어입니다. 즉, 변수의 타입이 실행 시점에 결정되며, 변수의 타입을 변경할 수 있습니다.
- TypeScript는 정적 타입 언어입니다. 변수의 타입은 선선 시점에 결정되며, 이후 변경할 수 없습니다. 이러한 특성은 개발자가 코드에서 오류를 더 쉽게 발견할 수 있도록 도와줍니다.
- TypeScript는 클래스, 인터페이스, 제네릭 등과 같은 고급 객체 지향 프로그래밍 기능을 제공합니다.
- 📃TypeScript를 사용해야 하는 이유
- 📋더 나은 에러 검출
- 정적 타입 검사를 통해, 개발자는 컴파일 시점에 코드의 오류를 더 쉽게 발견할 수 있습니다.
- 📋개발 도구(IDE)의 지원 향상
- 정적 타입 검사는 개발 도구에게 유용한 정보를 제공합니다. 이를 통해, 개발 도구는 더 나은 자동완성, 리팩토링 도구, 타입 검사 등을 제공할 수 있습니다.
- 📋향상된 문서화 및 코드 가독성
- TypeScript의 타입 시스템은 코드를 작성하는 개발자 뿐만 아니라 다른 개발자에게도 변수나 함수가 어떤 값을 가지거나 변환해야 하는지 명확히 알려줍니다. 이러한 코드는 팀 작업이나 큰 프로젝트에서 특히 중요합니다.
- TypeScript 설치 및 개발 환경 설정
- 📋Node.js 설치 : TypeScript는 Node.js 환경에서 실행되므로, 먼저 Node.js를 설치해야 합니다.
- 📋TypeScript 설치 : Node.js를 설치한 후에는, npm을 사용하여 TypeScript를 설치할 수 있습니다. 터미널에서 다음 명령어를 실행합니다.
npm install -g typescript - 📋텍스트 에디터 설치 : Vscode, subtime Text, Atom 등의 텍스트 에디터를 설치합니다. 이중 Vscode는 TypeScript에 대한 강력한 지원을 제공하므로, TypeScript 개발에 매우 적합합니다.
- 컴파일 언어 & 인터프리터 언어 & 트랜스파일 언어
컴파일언어, 인터프리터언어
-
컴파일러는 고수준 언어로 작성된 소스 코드를 한 번에 기계어나 다른 저수준 언어로 변환하는 프로그램입니다. 이 변환된 코드는 별도의 파일로 저장되며, 이 파일을 실행하며 프로그램을 동작시킵니다.
-
📜컴파일 언어의 특징
- 실행 속도가 빠름
- 저수준 언어로 변환된 코드를 배포하기에 코드에 대한 보안성이 용이
- 컴파일 과정에서 전체 코드에 대한 문법 오류를 확인 할 수 있습니다.
- 코드의 규모가 크다면 컴파일이 오래 걸릴 수 있습니다.
- 실행하기 전 반드시 컴파일 과정을 거쳐야 하기에 디버깅이 불편합니다.
- 코드의 변경이 생기면 반드시 컴파일을 다시 해야 합니다.
-
📜인터프리터는 고수준 언어로 작성된 소스 코드를 한 줄씩 읽어가면서 즉시 실행하는 프로그램입니다. 이는 별도의 변환과정이 없이 소스 코드를 직접 실행한다는 것을 의미합니다.
-
📜인터프리터 언어의 특징
- 코드의 변경과 실행을 매우 빠르게 할 수 있다보니 디버깅 등이 쉽다.
- 실행 속도가 느릴 수 있습니다.
- 문법이 잘못된 코드가 있더라도 실행해서 해단 코드를 호출하기 전까지는 에러가 발생하지 않습니다.
- 소스코드 그대로 실행하다 보니 코드에 대한 보안이 부족합니다.
- 패키지 매니저
-
패키지 매니저는 코드 라이브러리를 관리해주는 도구를 의미합니다.
-
NPM : Node.js에서 사용되는 패키지 매니저
-
PIP : Python에서 사용되는 패키지 매니저
-
Maven, Gradle : Java에서 사용되는 빌드 도구 겸 패키지 매니저
-
NuGet : .NET에서 사용되는 패키지 매니저
-
apt, yum : Linux에서 사용되는 패키지 매니저
-
Homebrew : macOS에서 사용되는 패키지 매니저
-
📜패키지 매니저를 사용해야 하는 이유
- 손쉬운 외부 패키지 설치
- TypeScript 파일 다운로드, 설치, 각종 설정 -> npm install typescript
- 프로젝트에 사용된 패키지 버전의 관리
- 설치된 패키지의 버전을 수동으로 추적해야 하고 이 정보를 별도 문서나 주석으로 남겨둬야 함 -> package.json과 같은 파일을 통해 자동으로 관리
- 패키지의 의존성 관리
- 각 패키지의 의존성을 직접 파악하고 필요한 패키지를 버전에 맞게 하나씩 설치 -> 자동으로 해줌