카테고리 없음

TypeScript 기본 문법 및 개념

만능 엔터테이너 2024. 8. 20. 16:09
728x90
반응형
SMALL

타입스크립트란?

타입스크립트는 별도의 새로운 언어가 아니라, 자바스크립트에 타입(type)을 추가한 확장 언어입니다. 새로 배우는 언어가 아니기 때문에 학습 난이도는 높지 않은 편이며, 처음에는 복잡해보이지만, 나중에 가도 복잡합니다.. (쉽게 쉽게 할거면 자바스크립트 쓰자.. 😉)

설치

타입스크립트로 작성된 코드를 실행하려면 타입스크립트 코드를 자바스크립트 코드로 ‘변환’해주는 작업이 필요합니다. 이러한 변환 작업을 전문 용어로 ‘컴파일(compile)’이라고 합니다. 컴파일을 하기 위해서 여러가지 방법이 있지만, 저희는 Node.js를 이용하는 방법으로 합니다.

Step 1

실습에 사용할 폴더를 하나 생성하여 비주얼 스튜디오 코드로 열어줍니다.

Step 2

비주얼 스튜디오 코드의 가장 루트 폴더 경로 내에서 아래와 같이 npm 패키지 초기화를 진행합니다.

 npm init -y // 기본 값으로 npm 초기화
 npm install typescript --save-dev // 개발모드로 설치
 node ./node_modules/typescript/bin/tsc --init  # 타입스크립트 초기화

Step 3

이제 아래와 같은 명령어로 타입스크립트 파일을 자바스크립트로 변환할 수 있습니다.

node ./node_modules/typescript/bin/tsc index.ts

예제

index.ts

function sum(a: number, b: number) {
  return a + b;
}
const a = sum(10, 20);
console.log(a);

변환

node ./node_modules/typescript/bin/tsc index.ts

index.js

function sum(a, b) {
    return a + b;
}
var a = sum(10, 20);
console.log(a);
{
  "compilerOptions": {
    // 컴파일된 JavaScript 코드가 호환될 ECMAScript의 버전을 지정합니다.
    // 여기서는 최신 ECMAScript 표준 버전으로 컴파일 됩니다.
    "target": "ESNext",

    // 모듈 시스템을 지정합니다. CommonJS 모듈 시스템은 Node.js에서 사용되는 표준입니다.
    // 컴파일된 코드는 CommonJS 모듈 형식을 따릅니다.
    "module": "commonjs",

    // 컴파일된 JavaScript 파일이 출력될 디렉토리를 지정합니다.
    // 여기서는 `./dist` 디렉토리에 컴파일된 파일이 저장됩니다.
    "outDir": "./dist",

    // CommonJS 모듈을 ES6 모듈처럼 사용할 수 있도록 추가적인 코드 변환을 수행합니다.
    // 주로 `import` 구문을 사용할 때 유용합니다.
    "esModuleInterop": true,

    // 파일 이름의 대소문자 일관성을 강제합니다.
    // 파일을 불러올 때 대소문자가 일치하지 않으면 오류를 발생시킵니다.
    // 이는 특히 대소문자를 구분하는 파일 시스템에서 유용합니다.
    "forceConsistentCasingInFileNames": true,

    // 엄격한 타입 검사를 활성화합니다.
    // 여러 가지 타입 검사 옵션을 포함하여 더욱 엄격한 타입 체크를 수행합니다.
    "strict": true,

    // .d.ts 파일의 타입 검사를 건너뜁니다.
    // 이는 컴파일 속도를 높이기 위해 유용합니다.
    "skipLibCheck": true,
  },

  // 컴파일 대상 파일을 지정합니다.
  // 여기서는 `src` 디렉토리 아래의 모든 `.ts` 파일을 포함합니다.
  "include": ["src/**/*.ts"],

  // 컴파일에서 제외할 파일을 지정합니다.
  // 여기서는 `node_modules` 디렉토리를 제외합니다.
  "exclude": ["node_modules"]
}


타입스크립트 with VSCode

설치

> npm i typescript -D
> npx tsc -v  # 버전 확인

> npm install -D ts-node
> npx ts-node -v # 버전 확인

Code Runner

# setting
# code-runner.excutorMap 추가
"code-runner.clearPreviousOutput": true,
**"code-runner.executorMap": {
  "typescript": "node_modules/.bin/ts-node"
},**

코드 저장 후 실행해보면 Code Runner로 구동 가능합니다.

📢 인코딩이 깨지는 사람은 아래처럼 설정 변경
"code-runner.executorMap": {
  "typescript": "node -r ts-node/register"
},

기본 타입

타입스크립트에서 추가된 기본 타입은 다음과 같습니다.

  • string
  • number
  • boolean
  • object
  • Array (대문자 주의)
  • tuple
  • any
  • null
  • undefined

string

string 타입은 문자열 타입입니다.

const str:string = "Hello World";

Number

number 타입은 숫자 타입입니다.

const num:number = 10;

boolean

boolean 타입은 논리형 타입입니다.

const agree:boolean = true;

object

object 타입은 객체 타입입니다.

const user:object = { name:"수코딩", age:20}

Array

Array 타입은 배열 타입입니다. 배열 타입은 조금 복잡합니다.

// 문자열 요소만 담긴 배열
const fruits:Array<string> = ['apple', 'banana', 'orange'];
const fruits:string[] = ['apple', 'banana', 'orange'];

// 숫자 요소만 담긴 배열
const luckyNumber:Array<number> = [10, 20, 30];
const luckyNumber:number[] = [10, 20, 30];

// 문자랑 숫자랑 섞인 배열
const mySave:Array<string | number> = [10, 'apple', 'banana', 20];
const mySave:(string | number)[] = [10, 'apple', 'banana', 20];

tuple

tuple 타입은 특정 형태를 갖는 배열을 의미합니다.

// arr 배열은 총 2개의 요소를 가지는데
// 첫 번째 요소는 문자열이고, 두 번째 요소는 숫자형이다.
const arr:[string, number] = ['apple', 10]; 

null / undefined

null 타입과 undefined 타입은 특수 자료형 타입입니다.

const data:null = null; 
const noting:undefined; 

any

any 타입은 타입스크립트에서 모든 타입을 허용하겠다는 의미입니다.

const arr:any = 10;

 

😵 타입스크립트를 배운 사람은 대부분 any 타입을 부정적으로 보는 사람이 많습니다. any 타입을 사용할 거면 뭐하러 타입스크립트를 사용하냐는 시선 때문입니다. 맞습니다. 되도록 any 타입은 지양해야 합니다. 하지만 잘만 활용하면 타입스크립트 개발시에 자바스크립트와 같은 유연함을 유용하게 사용할 수도 있습니다.

기본 타입 연습 문제

문제 1) 변수 타입 선언

다음 변수들을 선언하고, 타입을 지정해 보세요.

let name: __;        // 문자열 타입
let age: __;         // 숫자 타입
let isStudent: __;   // 불리언 타입
let hobbies: __;     // 문자열 배열 타입
let user: __;        // 객체 타입 (name과 age를 포함)
let uname: string; // 문자열 타입
let age: number; // 숫자 타입
let isStudent: boolean; // 불리언 타입
let hobbies: string[]; // 문자열 배열 타입
let user: { name: string; age: string }; // 객체 타입 (name과 age를 포함)

문제 2) 배열 타입 정의

다음 배열의 타입을 지정해주세요.

const arr = [1, 2, 3];
const arr2 = [1, [2, 3], 4];
const arr3 = [
  [
    [1, 2],
    [3, 4],
    ["a", "b"],
  ],
  [
    [5, 6],
    [7, 8],
    ["c", "d"],
  ],
];
const arr: number[] = [1, 2, 3];
const arr2: [number, number[], number] = [1, [2, 3], 4];
const arr3: [number[], number[], string[]][] = [
  [
    [1, 2],
    [3, 4],
    ["a", "b"],
  ],
  [
    [5, 6],
    [7, 8],
    ["c", "d"],
  ],
];


함수에 타입을 정의하는 법

자바스크립트의 함수에는 인자, 인수(매개변수)가 있습니다.

function  sum(a, b) { return a + b } // a, b는 인수 또는 매개변수
sum(10, 20);  // 10과 20은 인자 

매개변수에 타입 지정하기

매개 변수에 타입을 지정합니다.

function sum(a:number, b:number){ return a + b } // a, b는 숫자형 인자만 받을 수 있음
sum(10, 20); // ok
sum('a', 'b'); // not ok

반환값에 타입 지정하기

함수가 반환하는 값에도 타입을 지정할 수 있습니다.

function sum(a, b):number { return a + b } // 반환하는 값은 반드시 숫자형이어야 함.

옵셔널 파라미터

옵셔널 파라미터는 ? 기호로 표시합니다. ? 기호로 표시하면 타입으로 지정한 매개 변수를 생략할 수 있게 됩니다.

function sum(a:number, b:number) { return a + b }
sum(10); // 원래는 인자를 2개 작성하지 않으면 타입스크립트는 오류가 남

// but

function sum(a:number, b?:number) { return a + b }
sum(10); // 이렇게 옵션을 붙여주면, 해당 매개 변수는 옵셔널 파라미터가 되어서 인자 생략 가능.

 

함수타입

문제 1) 함수 타입 정의

다음 함수들을 타입스크립트로 작성하고 타입을 정의해 보세요.

  • 두 숫자를 더하고 결과를 반환하는 함수
  • 문자열을 받아서 문자열을 반환하는 함수
  • 불리언 값을 인자로 받아서 아무것도 반환하지 않는 함수 (void 반환)
const add = (a: number, b: number): number => a + b;
const getReturnValue = (a: string): string => a;
const loginStatus = (a: boolean): void => {};
  • 문장에서 가장 긴 단어를 반환하는 함수 (string , 배열아님)
const getLongsString = (str: string): string =>
  str.split(" ").sort((a, b) => b.length - a.length)[0];

console.log(getLongsString("Hello World"));
console.log(getLongsString("Hello a"));
  • 암스트롱 수 구하는 문제
/*
[연습문제 - 암스트롱 수 구하기]
난이도 ★★★★★

100부터 999까지 암스트롱 수를 구하세요 

&암스트롱 수란?

암스트롱의 수는 세 자리의 정수 중에서 각 자리의 수를 세 제곱한 수의 합과 자신이 같은 수를 말합니다. 
예를 들어 153 = 1 + 125 + 27 입니다. 
이와 같은 수를 암스트롱의 수라고 말합니다.


153 -> 1, 5 ,3
*/
const isArmstrongNumber = (num: number): boolean => {
  const digits = num.toString().split("").map(Number); // [1, 5, 3]
  const sumOfCubedDigits = digits.reduce(
    (acc, digit) => acc + Math.pow(digit, 3), // acc: 0, acc: 1, acc: 126, acc: 153
    0
  );
  return sumOfCubedDigits === num; // 암스트롱수? 원본숫자 === 각 자리수의 세제곱의 합
};

const printArmstrongNumbers = (): void => {
  for (let i = 100; i <= 999; i++) {
    if (isArmstrongNumber(i)) {
      console.log(i);
    }
  }
};

printArmstrongNumbers();

 


타입 오퍼레이터

자바스크립트의 OR(||) 연산자와 AND(&&) 연산자와 같은 역할을 하는 타입스크립트 오퍼레이터는 유니언 타입과 인터섹션 타입이 있습니다.

유니언 타입

유니언 타입은 OR(||) 연산자와 같은 역할을 하는 타입스크립트 오퍼레이터(|)로 여러 개의 타입을 결합한 타입을 말합니다. 유니언 타입은 연결된 타입 중 1개만 만족하면 됩니다.

const firstElements = (elements: number[] | string[]) => elements[0];
firstElements([1, 2, 3]); // 1
firstElements(["a", "b", "c"]); // 'a'

단, 유니언 타입은 여러 타입 중 어떤 타입과 일치하는지 보장할 수 없기 때문에 특정 타입의 메서드를 사용하려고 하면 에러가 납니다. 이럴 때는 아래와 같이 타입 가드(Type Guard)라는 개념을 사용하여, 해당 메서드를 사용할 수 있는 타입인지 명시해야 합니다.

const firstElements = (elements: number[] | string[]) => {
  // 타입가드
  const allNumber = elements.every((el) => typeof el === "number");
  return allNumber
    ? elements.reduce((acc, el) => acc + el, 0)
    : elements.reduce((acc, el) => acc + el);
};

console.log(firstElements([1, 2, 3])); // 1
console.log(firstElements(["a", "b", "c"])); // 'a'

인터섹션 타입

인터섹션 타입은 AND(&&) 연산자와 같은 역할을 하는 타입스크립트 오퍼레이터(*)를 사용하여 2개 이상의 타입을 결합한 타입을 말합니다. 인터섹션 타입은 연결된 타입을 모두 만족해야 합니다.

const user1: { name: string; age: number } & { title: string } = {
  name: "John",
  age: 30,
  title: "Software Engineer",
};

인터페이스

정의

인터페이스는 개체 타입을 지정할 때 사용하는 문법입니다.

문법

인터페이스는 다음과 같은 문법을 가집니다.

interface 타입명{
  속성:타입, 
  ...
}

기본

interface User {
  name: string;
}

const stu: User = {
  name: "sucoding",
};

function printName(this: User, age: number) {
  console.log(this.name, age);
}

const bindFunc = printName.bind(stu);
bindFunc(10);

병합

// interface1.ts
interface Person {
  name: string;
  age: number;
}

// interface2.ts
interface Person {
  email: string;
  phone?: string;
}

// main.ts
const john: Person = {
  name: "John Doe",
  age: 30,
  email: "john.doe@example.com",
  phone: "123-456-7890"
};

console.log(john);

상속

인터페이스는 상속이 가능합니다.

// 기본 인터페이스 정의
interface Animal {
  name: string;
  age: number;
  makeSound(): void;
}

// Animal 인터페이스를 상속받는 Dog 인터페이스 정의
interface Dog extends Animal {
  breed: string; // 추가적인 프로퍼티
  bark(): void; // 추가적인 메서드
}

const dog1: Dog = {
  name: "멍멍이",
  age: 3,
  breed: "진돗개",
  makeSound() {
    console.log("멍멍");
  },
  bark() {
    console.log("왈왈");
  },
};

인덱스 시그니처

interface IPerson {
  [key: string]: string | number;
}

const john: IPerson = {
  name: "John Doe",
  age: 30,
  email: "john.doe@example.com",
  phone: "123-456-7890",
};

console.log(john);

예제

변수에 인터페이스를 적용하는 법

interface IUser {
  name: string;
  age: number;
  introduce: () => string;
}

const user: IUser = {
  name: "sucoding",
  age: 20,
  introduce() {
    return `Hello, my name is ${this.name} and I'm ${this.age} years old.`;
  },
};

함수에 인터페이스를 적용하는 법

interface IAdd {
  (a: number, b: number): number;
}

const add: IAdd = (a, b) => a + b;
interface IPerson {
  name: string;
  age: number;
}

function averageAge(peolpe: IPerson[]): number {
  return peolpe.reduce((acc, person) => acc + person.age, 0) / peolpe.length;
}

const average = averageAge([
  { name: "John", age: 30 },
  { name: "Jane", age: 25 },
  { name: "Jim", age: 20 },
]);

console.log(average);

타입 별칭

정의

타입 별칭(type alias)는 type 키워드를 사용해서 타입을 지정하는 방식을 의미합니다.

예제

type TOption = "A" | "B" | "C";
const option: TOption = "A";
type TUser = {
  name: string;
  age: number;
};

function printUser(user: TUser): string {
  return `Name: ${user.name}, Age: ${user.age}`;
}


이넘

타입스크립트의 enum은 열거형(enum)을 정의하는 데 사용되는 데이터 타입입니다. 열거형은 관련된 상수 집합을 그룹화하여 코드의 가독성과 유지보수성을 높이는 데 도움을 줍니다. 각 열거형 값은 이름과 함께 숫자 또는 문자열로 매핑됩니다.

타입스크립트에서 enum을 사용하면 열거형을 정의하고, 이를 통해 상수 값을 보다 의미 있게 사용할 수 있습니다. 열거형은 다음과 같은 방식으로 정의하고 사용할 수 있습니다.

숫자 열거형 (Numeric Enum)

기본적으로, 타입스크립트의 열거형은 숫자 열거형으로 정의됩니다.

열거형의 각 멤버는 자동으로 0부터 시작하는 숫자 값을 갖습니다.

enum Direction {
  Up = 1,
  Down,
  Left,
  Right
}

console.log(Direction.Up); // 1
console.log(Direction.Down); // 2
console.log(Direction.Left); // 3
console.log(Direction.Right); // 4

// 숫자 값을 사용하여 이름을 얻을 수 있음
console.log(Direction[1]); // 'Up'

문자열 열거형 (String Enum)

문자열 열거형은 각 열거형 멤버가 문자열 값을 가지도록 정의할 수 있습니다. 문자열 열거형은 값이 명확하고 예측 가능하므로 더 직관적입니다.

enum Color {
  Red = "RED",
  Green = "GREEN",
  Blue = "BLUE"
}

console.log(Color.Red); // 'RED'
console.log(Color.Green); // 'GREEN'
console.log(Color.Blue); // 'BLUE'

이니셜라이즈된 열거형 (Const Enum)

const enum은 컴파일 타임 상수로 최적화되는 열거형입니다. 이 열거형은 런타임에 존재하지 않고, 컴파일할 때 상수로 대체됩니다. 주로 성능 최적화가 필요한 경우에 사용됩니다.

const enum Status {
  Success = 1,
  Error,
  Pending
}

let result = Status.Success;
console.log(result); // 1

문자열 및 숫자 혼합 열거형 (Heterogeneous Enum)

숫자와 문자열이 혼합된 열거형을 만들 수도 있지만, 이 방식은 권장되지 않습니다.

혼합된 열거형은 혼란을 초래할 수 있습니다.

enum Mixed {
  No = 0,
  Yes = "YES"
}

console.log(Mixed.No); // 0
console.log(Mixed.Yes); // 'YES'

열거형의 사용 예제

열거형은 주로 상태를 표현하거나, 관련된 상수 값들을 그룹화할 때 사용됩니다.

다음은 열거형을 활용한 간단한 예제입니다.

enum Weekday {
  Monday,
  Tuesday,
  Wednesday,
  Thursday,
  Friday,
  Saturday,
  Sunday
}

function isWeekend(day: Weekday): boolean {
  return day === Weekday.Saturday || day === Weekday.Sunday;
}

const today = Weekday.Saturday;
console.log(`Is today a weekend? ${isWeekend(today)}`); // Is today a weekend? true

요약

  • 숫자 열거형: 자동으로 숫자 값이 할당되며, 기본적으로 0부터 시작합니다.
  • 문자열 열거형: 명시적으로 문자열 값을 가지며, 값이 명확하고 예측 가능합니다.
  • 상수 열거형 (const enum): 컴파일 타임에 상수로 대체되며, 런타임에 존재하지 않습니다.
  • 혼합 열거형: 숫자와 문자열을 혼합하여 사용할 수 있지만, 혼란을 초래할 수 있으므로 사용에 주의가 필요합니다.

열거형은 코드의 가독성을 높이고, 의미 있는 상수 집합을 쉽게 정의할 수 있게 해줍니다.


제네릭

정의

제네릭은 타입을 미리 지정하지 않고 사용하는 시점에 타입을 정의해서 쓸 수 있는 문법을 말합니다.

예제

// 제네릭 함수
function identity<T>(value: T): T {
  return value;
}

console.log(identity(42));       // 42
console.log(identity("hello"));  // hello
const firstElement = (elements: number[] | string[]) => elements[0];
firstElement([1, 2, 3]); // 1
firstElement(["a", "b", "c"]); // 'a'
const firstElement = <T>(elements: T[]): T => {
  return elements[0];
};
firstElement([1, 2, 3]); // 1
firstElement(["a", "b", "c"]); // 'a'
// before
const printString = (x: string) => console.log(x);
const printNumber = (x: number) => console.log(x);
const printBoolean = (x: boolean) => console.log(x);

printString("Hello, world!");
printNumber(42);
printBoolean(true);

// after
const printValue = <T>(x: T) => console.log(x);

printValue("Hello, world!");
printValue(42);
printValue(true);

---

function getRandomKeyValuePair<T>(obj: { [key: string]: T }) {
  const keys = Object.keys(obj);
  const randomKey = keys[Math.floor(Math.random() * keys.length)];
  return { key: randomKey, value: obj[randomKey] };
}

const stringObject = { a: "a", b: "b", c: "c" };
const randomStringPair = getRandomKeyValuePair<string>(stringObject);
console.log(randomStringPair);

---

function filterArray<T>(array: T[], condition: (item: T) => boolean): T[] {
  return array.filter((item) => condition(item));
}

const numberArray = [1, 2, 3, 4, 5];
const evenNumbers = filterArray(numberArray, (num) => num % 2 === 0);
console.log(evenNumbers); // [2, 4]

const stringArray = ["hello", "world", "typescript"];
const longWords = filterArray(stringArray, (word) => word.length > 5);
console.log(longWords); // ["typescript"]

인터페이스에도 사용가능

interface Box<T> {
  value: T;
  getValue(): T;
}

const numberBox: Box<number> = {
  value: 123,
  getValue() {
    return this.value;
  }
};

const stringBox: Box<string> = {
  value: "hello",
  getValue() {
    return this.value;
  }
};

console.log(numberBox.getValue()); // 123
console.log(stringBox.getValue()); // "hello"

타입 별칭

type Result<T> = {
  success: boolean;
  data: T;
};

const result1: Result<number> = {
  success: true,
  data: 42
};

const result2: Result<string> = {
  success: false,
  data: "error"
};

console.log(result1); // { success: true, data: 42 }
console.log(result2); // { success: false, data: "error" }

타입 제약

extends 키워드를 사용한 타입 제약은 제네릭의 타입을 제한하고 싶을 때 사용합니다.

function logLength<T extends { length: number }>(item: T): void {
  console.log(item.length);
}

logLength("Hello"); // 5
logLength([1, 2, 3]); // 3
// logLength(123); // 오류: number는 length 프로퍼티가 없음
interface IResponse<T> {
  status: number;
  data: T;
}

function toUppercase<T extends { toUpperCase: () => T }>(value: T): T {
  return value.toUpperCase();
}

toUppercase<string>("abc");
toUppercase<number>(123); // error, toUppercase()가 없음
const getSize = <T>(arr: T[]) => {
  return arr.length;
};

console.log(getSize<number>([1, 2, 3]));
console.log(getSize<string>(["a", "b", "c"]));
console.log(getSize<boolean>([true, false]));

function getRetunValue<T>(arr: T): T {
  return arr;
}
console.log(getRetunValue<number[]>([1, 2, 3])); // [1, 2, 3]
console.log(getRetunValue<string[]>(["a", "b", "c"])); // [1, 2, 3]

type ApiResponse = {
  data: object;
  status: number;
};

type TApiResponse<T> = {
  data: T;
  status: number;
};

// API Response
const userResponse: TApiResponse<{ id: number; name: string }> = {
  data: { id: 1, name: "Jonh" },
  status: 200,
};

const todoResponse: TApiResponse<{
  id: number;
  text: string;
  completed: boolean;
}> = {
  data: { id: 1, text: "아침먹기", completed: false },
  status: 200,
};

function filterArray<T>(arr: T[], condition: (item: T) => boolean): T[] {
  return arr.filter((item) => condition(item));
}

const numberArray = [1, 2, 3, 4, 5];
const isEven = (num: number) => num % 2 === 0;
const evenNumbers = filterArray(numberArray, isEven);
console.log(evenNumbers);

 

재네릭 연습문제

문제 1)

다음 함수들을 타입스크립트로 작성하고 타입을 정의해 보세요.

  • 배열을 입력받아 배열의 요소들을 역순으로 반환하는 제네릭 함수를 작성하세요.
function reverse<T>(arr: T[]): T[] {
    return arr.slice().reverse();
}

// 사용 예제
const numArray = [1, 2, 3];
const reversedNumArray = reverse(numArray);  // [3, 2, 1]

const strArray = ["a", "b", "c"];
const reversedStrArray = reverse(strArray);  // ["c", "b", "a"]

 

Todo List 코드 타입

아래의 코드는 Todo List에서 사용되는 코드를 자바스크립트로 작성한 코드입니다.

index.ts

const todos = [];

const addTodo = (text) => {
  const todo = {
    id: todos.length + 1,
    text,
    completed: false,
  };
  todos.push(todo);
};

const removeTodo = (id) => {
  const findIndex = todos.findIndex((todo) => todo.id === id);
  todos.splice(findIndex, 1);
};

const toggleTodo = (id) => {
  const find = todos.find((todo) => todo.id === id);
  find.completed = !find.completed;
};

위 코드를 타입스크립트로 변경하세요.

interface ITodo {
  id: number;
  text: string;
  completed: boolean;
}
const todos: ITodo[] = [];
const addTodo = (text: string) => {
  const todo: ITodo = {
    id: todos.length + 1,
    text,
    completed: false,
  };
  todos.push(todo);
};

const removeTodo = (id: number) => {
  const findIndex = todos.findIndex((todo) => todo.id === id);
  todos.splice(findIndex, 1);
};

const toggleTodo = (id: number) => {
  const find = todos.find((todo) => todo.id === id);
  if (find) find.completed = !find.completed;
};

 

[스나이퍼 팩토리 리액트 2기 과정]

본 학습 자료 및 코드는 수코딩님의 자료를 이용하였습니다. [수코딩(https://www.sucoding.kr)] 출처

728x90
반응형
LIST