[1] 기본 ts 문법들과 미션

Kim TaeHyeong·2026년 9월 18일

UMC

목록 보기
1/12

0. TypeScript란 & 설치

JavaScript의 상위로, 오류 가능성이 높은 JS를 컴파일 단에서 잘 잡기 위해서 만들어졌다.
문법이 엄격하여 사전에 오류 진단이 가능하다.
런타임 오류 => 컴파일 오류 로 바뀌는 경우가 많다.

npm 설치 후

npm init
npm add -D typescript

로 설치
tsconfig.json을

{
  "compilerOptions": {
    "target": "ES2022",
    "rootDir": "./src",
    "outDir": "./dist",
    "strict": true
  },
  "include": ["src/**/*.ts"]
}

로 하면, ./src 밑의 ts 구조를 ./dist 밑의 js 구조로 바꾸겠다는 것이다.
예시로
src/tmp.ts
src/asdf/tmp.ts
=>
dist/tmp.js
dist/asdf/tmp.ts
로 된다는 것이다.

pnpm exec tsc

로 컴파일 하면 ./dist에 생긴다

node 파일명

으로 컴파일된 js 실행 가능하다

주의점

vscode의 ts 확장 깔면 약간 문제 생길 가능성 있다
우선, ts는 변수의 타입을 여러 번 선언할 수 없다

연습하다보면 변수명이 자주 겹치는데,
이 문제는 ts 파일 밑에 export {};를 붙여서 해결 가능하다
모듈화를 해서 각각의 공간만 이용한다는 뜻이다.

이 경우, export {}; 가 오류가 날 수 있는데,

{
    "compilerOptions": {
        "target": "ES2020",
        "module": "CommonJS",
        "moduleDetection": "force",
        "strict": true,
        "esModuleInterop": true,
        "forceConsistentCasingInFileNames": true,
        "skipLibCheck": true
    }
}

로 모듈 moduleDetection force가 각 파일을 모듈로 처리한다는 말로,
예제 풀기 좋은 환경을 만들 수 있다.

추가적으로, 파일 자동 포멧 생성이랑 컴파일이 귀찮아서 chatGPT 도움 받아서 자동 기능 만들었다.
https://github.com/kysth0707/ezts
vscode가 .vscode 인식을 가끔 못할 때는 tasks.json을 새로 저장하면 된다.

#1. print

/*
 * 제목 : print
 * 
 * < 요약 >
 * python과 비슷함
 * +로 할 수 있으나, python의 fstring처럼 ${}로 내부에 작성 가능
 * 그러나, `(하이픈, ~에 있는 친구)를 써야함
 * 
 * [2026/09/16 11:22:09]
 */

const courseName = "TypeScript";
console.log("이번 주 학습 주제: " + courseName);
console.log(`이번 주 학습 주제: ${courseName}`);

export {};

#2. type 오류 찾기

/*
 * 제목 : 오류찾기
 * 
 * < 요약 >
 * type 안 맞게 하면 오류
 * 
 * [2026/09/17 00:29:36]
 */

// Before
/*function introduceStudent(studentName: string, currentLevel: number) {
    return studentName + " 님은 현재 " + currentLevel + "레벨이에요.";
  }
  
  introduceStudent("광수", "1");*/

// After
function introduceStudent(studentName: string, currentLevel: number) {
return studentName + " 님은 현재 " + currentLevel + "레벨이에요.";
}

introduceStudent("광수", 1);

export {};

#3. 원시 값, 객체 값, 타입 선언

/*
 * 제목 : 원시 값, 객체 값, 타입 선언
 * 
 * < 요약 >
 * 원시 값은 value 비교, 객체 값은 주소 비교
 * 그래서 lodash 같은 deep 비교 필요
 * import _ from 'lodash';
 * console.log(_.isEqual(objA, objB));
 * 
 * array라고 하지만 list(dynamic array)임.
 * [] 꼴로 리스트 자주 작성. var는 scope 탈출해서 안 씀.
 * 
 * [2026/09/17 00:32:16]
 */

// 1
const firstMember = { name: "광수" };
const secondMember = { name: "광수" };
const sameMember = firstMember;

console.log(firstMember === secondMember); // false {}로 객체임
console.log(firstMember === sameMember); // true

//2
let a = '123'; // 알아서 string
let b = 123; // 알아서 number
let c: string = '123'; //내가 지정

//3
const tmp: string[] = ["ㅇ"];
tmp.push("ㅎㅇ요"); //const 라고 쓸 수 없는 게 아님. 주소가 고정.

const tmp2: readonly string[] = ["ㅇ"];
// tmp2.push("ㅎㅇ"); //오류남

const studentRecord: [string, number] = ["광수", 1]; //tuple

const num: number[][] = [[1,2],[3]];
const num2: Array<Array<number>> = [[1,2],[3]];
//뭔가 c# 같음. List<int> scores = new List<int>();
// 물론 [] 꼴을 권장

//4
if (true)
{
    var itsvar = '';
    let itslet = '';
}
itsvar; //오류 안남. 즉, scope를 탈출
// itslet; //오류남


export {};

#4. 객체와 함수에 타입

/*
 * 제목 : 객체에 커스텀 타입 붙이기
 * 
 * < 요약 >
 * type 으로 정의 가능
 * 
 * [2026/09/17 00:43:03 / 1_typedef.ts]
 */

const student: {name:string, age:number} = {name:"ㅇㅇ", age:0};

type studentType = {name:string, age:number, gender?: boolean}; //python의 class 느낌
type studentType2 = {name:string; age:number, gender?: boolean}; //comma 대신 semicolon 써도 ㄱㅊ

const gildong: studentType = {
    name : "길동",
    age : 1,
} //instance 느낌
console.log(gildong);
//{ name: '길동', age: 1 }
//undefined로 설정되지 않고 아예 없다.

const gildong2: studentType = {
    name : "길동",
    age : 1,
    gender: true,
}
console.log(gildong2);
//{ name: '길동', age: 1, gender: true }
/*
 * 제목 : 함수에 type def
 * 
 * < 요약 >
 * python은 class에서 그쳤다면 js는 def의 입출력에 관해서도 class를 지원하는 듯
 * 
 * [2026/09/17 12:34:37 / week1-typescript/4/2_functypedef]
 */

function printGreeting(studentName: string) {
    console.log("반가워요, " + studentName + " 님!");
}
function printGreeting2(studentName: string): void {
    console.log("반가워요, " + studentName + " 님!");
}

const add = (a: number, b: number) => {
    return a + b;
};
const add2 = (a: number, b: number): number => {
    return a + b;
};
const add3 = (a: number, b: number): number => a + b;

type addition = (a: number, b: number) => number;
//숫자, 숫자 입력이고 숫자 리턴할거임
const add4: addition = (c, d) => c + d;
//숫자, 숫자 입력받고 숫자+숫자=(숫자) 리턴
/*
 * 제목 : type override 살펴보기
 * 
 * < 요약 >
 * 같은 타입이면 never 오류 안남. 다른 타입이면 오류남.
 * 즉, 타입&이름을 검사. 따라서 내용 override는 주의해야 할 듯
 * 
 * [2026/09/17 12:43:00 / week1-typescript/4/3_type]
 */

type MemberProfile = {
    name: string;
};
  
type GithubProfile = {
    githubId: string;
};

type MemberWithGithub = MemberProfile & GithubProfile;

const gwangsooProfile: MemberWithGithub = {
    name: "광수",
    githubId: "gwangsoo",
};

console.log(gwangsooProfile.name, gwangsooProfile.githubId);

//override test
type a = {age:number, name:number};
type b = {name:string};
type c = a & b;
// let tmp:c = {age:1, name:12};
// 'number' 형식은 'never' 형식에 할당할 수 없습니다.ts(2322)


type tmp = number & string;
// any로 우회하여 "임의의 값"을 주입
const dummy = "test" as any as tmp;
//test 를 any로 변환
//any를 tmp(never)로 변환. 이를 허용해줌

// 자바스크립트 실행 시점의 타입을 출력 (결과는 "string")
console.log(typeof dummy); 



type IsEqual<T, U> = 
  (<G>() => G extends T ? 1 : 2) extends 
  (<G>() => G extends U ? 1 : 2) 
    ? true 
    : false;
/*T extends U (T가 U에 포함되는가?)라고 물어보면, 
타입스크립트가 자기 마음대로 유니온 타입(A | B) 같은 
복잡한 걸 쑥쑥 쪼개면서 "어? 비슷하네? 참(true)!" 
하고 대충 넘어가는 버그가 생깁니다. 

1. G라는 빈 상자(제네릭)를 만듭니다.
2. 그 상자에다가 "네가 가진 타입 T와 똑같이 반응하는지 테스트해 볼게"라고 시킵니다.
3. 그리고 그 테스트 결과를 함수 타입으로 감싸버립니다.

이렇게 함수 타입 안으로 T와 U를 숨겨버리면, 
타입스크립트는 유니온 타입 등을 제멋대로 쪼개지 못하고 
오직 두 타입의 구조가 완벽하게 일치할 때만 같다고 인정하게 됩니다.
*/


type tmp1 = {
    a: string;
}

type tmp2 = {
    a: string;
}
type tmp1andtmp2 = tmp1 & tmp2;

type tmp3 = {
    a: string;
    b: number; // 내용이 다른 확장된 인터페이스
}

//내용 같음
type Result1 = IsEqual<tmp1, tmp1andtmp2>; 
// false

// Case 2: 내용이 다른 경우 (tmp1과 tmp3)
type Result2 = IsEqual<tmp1, tmp3>; 
// false
/*
 * 제목 : interface 테스트
 * 
 * < 요약 >
 * 
 * 
 * [2026/09/17 12:54:20 / week1-typescript/4/4_interface]
 */

type StudentName = string;

interface StudyMember {
  name: StudentName;
}

interface StudyMember {
  level: number;
} //override 및 

const member: StudyMember = {
  name: "광수",
  level: 1,
};



interface Parent { a: string; }
interface Child extends Parent { b: number; } // Parent와 Child는 별개의 존재
interface Child2 extends Parent { a: string; }
// interface Child2 extends Parent { a: number; }
// 후속 속성 선언에 같은 형식이 있어야 합니다. 
// 'a' 속성이 'string' 형식이어야 하는데 여기에는 'number' 형식이 있습니다.ts(2717)



interface asdf { a: string; }
// 여기서 새로운 걸 만드는 게 아니라, 원래 있던 asdf 자체가 커짐
interface asdf { b: number; }


//오류 테스트
interface tmp {a: string};
const b:tmp = {a : 'ㅇㅇ'};
console.log(b);

interface tmp {a: string};
// 그냥 불필요한 코드가 되어버림.
console.log(b);



interface tmp2 {a: string};
// interface tmp2 {a: number};
// 후속 속성 선언에 같은 형식이 있어야 합니다. 
// 'a' 속성이 'string' 형식이어야 하는데 여기에는 'number' 형식이 있습니다.ts(2717)

//type은 &(override)에서 오류 안남. 값 대입할 때만 오류남
//interface는 override에서 오류 남. << 이게 장점



// 1. 두 타입이 같은지 판별하는 유틸리티 타입 (Conditional Type 활용)
type IsEqual<T, U> = 
  (<G>() => G extends T ? 1 : 2) extends 
  (<G>() => G extends U ? 1 : 2) 
    ? true 
    : false;
/*T extends U (T가 U에 포함되는가?)라고 물어보면, 
타입스크립트가 자기 마음대로 유니온 타입(A | B) 같은 
복잡한 걸 쑥쑥 쪼개면서 "어? 비슷하네? 참(true)!" 
하고 대충 넘어가는 버그가 생깁니다. 

1. G라는 빈 상자(제네릭)를 만듭니다.
2. 그 상자에다가 "네가 가진 타입 T와 똑같이 반응하는지 테스트해 볼게"라고 시킵니다.
3. 그리고 그 테스트 결과를 함수 타입으로 감싸버립니다.

이렇게 함수 타입 안으로 T와 U를 숨겨버리면, 
타입스크립트는 유니온 타입 등을 제멋대로 쪼개지 못하고 
오직 두 타입의 구조가 완벽하게 일치할 때만 같다고 인정하게 됩니다.
*/


// --- 테스트용 인터페이스 ---
interface tmp1 {
  a: string;
}

interface tmp2 {
  a: string; // tmp1과 완전히 같은 내용
}

interface tmp3 {
  a: string;
  b: number; // 내용이 다른 확장된 인터페이스
}


// --- 2. 비교 실행 및 결과 확인 ---

// Case 1: 완전히 같은 타입인 경우 (tmp1과 tmp2)
type Result1 = IsEqual<tmp1, tmp2>; 
// true (마우스 올려보면 true로 나옴)

// Case 2: 내용이 다른 경우 (tmp1과 tmp3)
type Result2 = IsEqual<tmp1, tmp3>; 
//  false (내용이 다르므로 false)
/*
 * 제목 : 미니실습 오류고치기
 * 
 * < 요약 >
 * ...가 python의 unpacking인 *나 **랑 똑같다.
 * 즉, 위에 기본값 쓰고 밑에서 유저 인풋 받으면
 * 자연스레 오버라이드 되면서 기본값 설정 ㄱㄴ
 * 
 * [2026/09/17 13:44:07 / week1-typescript/4/5_mini_mission]
 */

/*before
type StudyMember = {
  name: string;
  level: number;
  isLeader: boolean;
};

const member: StudyMember = {
  name: "광수",
  level: "1",
};

function createMemberCard(studyMember: StudyMember) {
  return studyMember.name + " 님, " + studyMember.level + "레벨";
}

console.log(createMemberCard(member));
*/

type StudyMember = {
    name: string;
    level: number;
    isLeader: boolean;
  };
  
  const member: StudyMember = {
    name: "광수",
    level: 1,
    isLeader: false,
  };
  
  function createMemberCard(studyMember: StudyMember) {
    return studyMember.name + " 님, " + studyMember.level + "레벨";
  }
  
  console.log(createMemberCard(member));


//is Leader 기본값 설정하기
type settings = {
    name: string;
    level: number;
    isLeader?: boolean;
    theme?: "dark" | "light";
};

const input: settings = {
    name: "길동",
    level: 1,
    theme: "dark"
}; //유저가 쓴 것. isLeader는 없다

const final: settings = {
    isLeader: false, //기본값
    theme: "light", //기본값
    ...input
}
console.log(input);
//{ name: '길동', level: 1, theme: 'dark' }
console.log(final);
//{ isLeader: false, theme: 'dark', name: '길동', level: 1 }

//... 은 python의 unpacking (*나 **) 문법이랑 걍 똑같음

#5. union type과 type 좁히기

/*
 * 제목 : union type
 * 
 * < 요약 >
 * ts 컴파일러 생각보다 더 똑똑함
 * 오류를 사전에 정말 잘 막아준다.
 * 
 * [2026/09/17 13:54:55 / week1-typescript/5/1_uniontype]
 */

function printMemberId(memberId: string | number) {
    console.log(memberId);
}

printMemberId("member-01");
printMemberId(1);

function formatMemberId(memberId: string | number) {
    if (typeof memberId === "number" || typeof memberId === "string")
    {
        memberId //(parameter) memberId: string | number
    }
    if (typeof memberId === "string") {
        return memberId.toUpperCase();
    }
    if(typeof memberId === "function")
    {
        memberId
        //(parameter) memberId: never
    }
    if (typeof memberId === "number" || typeof memberId === "string")
    {
        memberId
        // 여기서 memberId가 number로만 나오는 이유
        //위에서 memberId가 string이면 return해서 나가기 때문에.

        if (typeof memberId === "string") {
            memberId
            //그러니 number인데 string => never 됨
        }
    }

    return "MEMBER-" + memberId;
}




type MemberRole = "leader" | "member";
type AttendanceStatus = "present" | "late" | "absent";

const gwangsooRole: MemberRole = "leader";
const todayStatus: AttendanceStatus = "present";

const tmp: MemberRole = "leader";
// const tmp2: MemberRole = "asdfasf";
// '"asdfasf"' 형식은 'MemberRole' 형식에 할당할 수 없습니다.ts(2322)
//오타 막아줘서 아주 중요한 듯
/*
 * 제목 : 미니실습
 * 
 * < 요약 >
 * 
 * 
 * [2026/09/17 14:03:39 / week1-typescript/5/2_mini_mission]
 */

type MemberRole = "leader" | "member";

function getRoleText(role: MemberRole): string
{
    if(role === "leader") return "스터디를 이끌어요."
    return '스터디에 참여해요.'
}

getRoleText("leader");
getRoleText("member");
// getRoleText("hi");
// '"hi"' 형식의 인수는 'MemberRole' 형식의 매개 변수에 할당될 수 없습니다.ts(2345)

#6 null & undefined

/*
 * 제목 : null과 undefined
 * 
 * < 요약 >
 * 
 * 
 * [2026/09/17 14:17:52 / week1-typescript/6/1_null_undefined]
 */

type StudyMember = {
    name: string;
    githubId?: string;
};

const members: StudyMember[] = [
    { name: "광수", githubId: "gwangsoo" },
    { name: "지수" },
];

let selectedMember: StudyMember | null = null;
const foundMember = members.find((member) => member.name === "현우");
//1개만 가져옴
//found_member = next((m for m in members if m.name == "현우"), None)
//next(generator, 기본)
//과 동일

console.log(selectedMember); // null
console.log(foundMember); // undefined



console.log(Boolean(false)); // false
console.log(Boolean(0)); // false
console.log(Boolean("")); // false
console.log(Boolean("false")); // true
console.log(Boolean([])); // true
console.log(Boolean({})); // true
//이런 비직관적인 내용 때문에 직접 비교가 안전

// foundMember가 undefined.
// githubId가 undefined로 반환
const githubId = foundMember?.githubId;
// const githubId2 = foundMember.githubId;
// 'foundMember'은(는) 'undefined'일 수 있습니다.ts(18048)




const studyHour: number | undefined = 0;

console.log(studyHour || 1); // 1
//studyHour가 falsy => 1씀
console.log(studyHour ?? 1); // 0
//studyHour가 null | undefined => 1씀
//즉, 모든 falsy 대체하려면 ||


const nickname: string | null = "";

console.log(nickname || "닉네임 없음"); // "닉네임 없음"
console.log(nickname ?? "닉네임 없음"); // ""


const displayGithubId = foundMember?.githubId ?? "등록되지 않음";
//undefined ?? "등록되지 않음"; => "등록되지 않음"
console.log(displayGithubId);

// ! <- 반드시 값이 있다. non-null
// const tmp = foundMember!.name;
// console.log(tmp);
// 그러나 undefined 였으니 컴파일에서 오류남
/*
 * 제목 : 미니미션
 * 
 * < 요약 >
 * 
 * 
 * [2026/09/17 14:27:53 / week1-typescript/6/2_mini_mission]
 */

type StudyMember = {
    name: string;
    githubId?: string;
};

const members: StudyMember[] = [
    { name: "광수", githubId: "gwangsoo" },
    { name: "지수" },
];

const selectedMember: StudyMember | null = null;

const foundMember = members.find((member) => member.name === "현우");
if(foundMember !== undefined)
{
    console.log(foundMember);
}

const studyHour: number = 0;

console.log(studyHour || 123); //123
console.log(studyHour ?? 123); //0

const targetMember: StudyMember = members[1];
console.log(targetMember?.githubId ?? "등록되지 않음");

#7 any unknown

/*
 * 제목 : any랑 unknown
 * 
 * < 요약 >
 * unknown은 검사해야 함.
 * 
 * [2026/09/18 01:02:25 / week1-typescript/7/1_unknown]
 */

function tmp(name: any)
{
    return name.toUpperCase();
    // string 아니면 오류 가능
}

function tmp2(name: unknown)
{
    if(typeof name === "string")
    {
        return name.toUpperCase();
    }
}

// tmp(1) 오류
tmp2("a")




function isActuallyString(val: unknown): val is string {
    // 런타임에는 사실 string이 아니거나 조작된 값을 반환하더라도 
    // 타입 시스템 입장에서는 string이라고 믿게 만듦
    return true;
}
//:변수 is 타입
//이 함수가 true 리턴하면, 변수는 타입
/*
function 함수이름(매개변수: 타입): [매개변수이름] is [바뀌길 원하는 타입] {
    return 참/거짓;
}
*/

function tmp3(a: unknown) {
    if (isActuallyString(a)) {
        // 컴파일러는 여기서 a가 string이라고 믿지만, 실제 값은 아닐 수 있음
        a.toUpperCase(); 
    }
}

// tmp3(12) 오류
/*
 * 제목 : 미니미션
 * 
 * < 요약 >
 * 
 * 
 * [2026/09/18 01:12:38 / week1-typescript/7/2_mini_mission]
 */

function formatStudyWeek(val : unknown)
{
    if(typeof val === "number")
    {
        return `현재 ${val}주차에요.`;
    }
    if(typeof val === "string")
    {
        return `입력한 주차: ${val}`;
    }
    return "주차를 확인할 수 없어요."
}

console.log(formatStudyWeek(1));
console.log(formatStudyWeek("1"));
console.log(formatStudyWeek(true));
console.log(typeof formatStudyWeek(true)); //string

#8 generic

/*
 * 제목 : generic
 * 
 * < 요약 >
 * 객체 만들 때 {value} 면 {value : value의값} 으로 됨
 * type이 오른쪽으로 흐름
 * 
 * [2026/09/18 01:15:44 / week1-typescript/8/1_generic]
 */

function keepVal<theType>(value: theType): theType
{
    return value;
}

console.log(typeof keepVal<string>("ㅎㅇ")); //string




function tmp<T>(value: T)
{
    return { value };
}

function tmp2<T>(value: T): {value: T}
{
    return { value: value };
    // tmp 함수랑 같음
}

console.log(tmp<string>("ㅎㅇ").value);
console.log(tmp2<number>(123).value);





function createBox(value: any) {
    return { value };
}

const box = createBox(100).value;
// (property) value: any
// ts가 에러를 잡아주지 못함! (런타임에 터짐)





type NamedMember = {
    name: string;
};

function getMemberName<T extends NamedMember>(member: T) {
    return member.name;
}

//getMemberName({age:1});
//'{ age: number; }' 형식의 인수는 
//'NamedMember' 형식의 매개 변수에 할당될 수 없습니다.
//최소 조건인 name:string이 없음.

console.log(getMemberName({age:1} as any));
//빨간 줄 안 뜸
//undefined

console.log(getMemberName<any>({age:1}));
//undefined

console.log(getMemberName({name:"ㅎㅇ", age:1}));
/*
 * 제목 : 미니 실습
 * 
 * < 요약 >
 * 
 * 
 * [2026/09/18 13:01:36 / week1-typescript/8/2_mini_mission]
 */

type member = {
    name: string
}

function createBox<T>(value: T)
{
    return {value};
}

createBox("12");
createBox(12);

const tmp: member = {name : "ㅎㅇ"};
createBox(tmp);

#9. strict

/*
 * 제목 : 미니 실습 오류 찾기
 * 
 * < 요약 >
 * 
 * 
 * [2026/09/18 13:03:40 / week1-typescript/9/1_mini_mission]
 */

/*before
type WeeklyGoal = {
  title: string;
  targetCount: number;
};

const weeklyGoal: WeeklyGoal = {
  title: "TypeScript 예제 연습",
  targetCount: "3", <- 여기 틀림
};

function printGoal(goal: WeeklyGoal): string {
  console.log(goal.title); <-리턴이 없음
}
*/

type WeeklyGoal = {
    title: string;
    targetCount: number;
  };
  
const weeklyGoal: WeeklyGoal = {
    title: "TypeScript 예제 연습",
    targetCount: 3
};

function printGoal(goal: WeeklyGoal): string {
    console.log(goal.title);
    return goal.title;
}
//반환 타입 명시한 이유
//보통 프린트 잘 됐는지 체크하려고 씀
//근데 그러면 boolean 리턴이 낫지 않을까?

#선택미션

/*
 * 제목 : 선택미션
 * 
 * < 요약 >
 * 
 * 
 * [2026/09/18 13:36:30 / week1-typescript/optional_mission]
 */

function formatMemberId(input: unknown): string
{
    if(typeof input === "number")
    {
        return `ID번호 : ${input}`
    }
    if(typeof input === "string")
    {
        return `ID텍스트 : ${input}`
    }
    return `ID?? : ${input}`
}

#필수미션

/*
 * 제목 : 필수 미션
 * 
 * < 요약 >
 * 
 * 
 * [2026/09/18 13:39:20 / week1-typescript/main_mission]
 */

//회원의 ID, 이름, 역할과 선택 값인 GitHub 아이디를 타입으로 표현하고, 서로 다른 정보를 가진 회원 두 명 이상을 작성해요.
type typeMember = {
    ID : number,
    name : string,
    githubID? : string,
};

const dataMember: typeMember[] = [
    {ID:1, name:"ㅇㅇ"},
    {ID:2, name:"ㄴㄴ", githubID:"nono"},
]

//회원 ID로 정보를 찾아 안내 문구를 만들고, GitHub 아이디가 없는 회원과 존재하지 않는 회원도 오류 없이 처리해요.
function getMemeberByID(targetID: number): typeMember | undefined
{
    return dataMember.find((member) => member.ID === targetID);
}

function getInfoTextByMember(targetMember: typeMember | undefined): string
{
    if(typeof targetMember === "undefined")
    {
        return `회원이 존재하지 않습니다.`
    }
    return `ID : ${targetMember.ID}
    Name : ${targetMember.name}
    GithubID : ${targetMember.githubID ?? "없음"}
    `
}

//회원 ID 1, 2, 999를 전달한 결과를 확인하고 pnpm exec tsc --noEmit, 컴파일과 실행을 모두 완료해요.
const IDsToCheck: number[] = [1, 2, 999];

IDsToCheck.forEach(targetID => {
    console.log(`ID : ${targetID}인 회원을 확인 중..`);
    const targetMember = getMemeberByID(targetID);
    const infoText = getInfoTextByMember(targetMember);

    console.log(infoText);
});


/*
ID : 1인 회원을 확인 중..
ID : 1
    Name : ㅇㅇ
    GithubID : 없음
    
ID : 2인 회원을 확인 중..
ID : 2
    Name : ㄴㄴ
    GithubID : nono
    
ID : 999인 회원을 확인 중..
회원이 존재하지 않습니다.
*/


  • TypeScript와 정적 타입 검사
    • JavaScript와 비교했을 때 TypeScript는 오류를 언제, 어떤 방식으로 확인하나요? 주로 런타임 ⇒ 컴파일.
    • 컴파일 타임 오류와 런타임 오류는 어떤 차이가 있나요? 실행 전 오류 vs 실행 중(서비스 중) 오류 ⇒ 안전성 문제
    • TypeScript의 타입 정보가 실행되는 JavaScript에 남지 않는 이유는 무엇일까요? ts는 js의 상위로, js로 변환 시켜주는 역할이기에. js는 타입 명시 없음. 그래서 ts 씀
  • 타입 추론과 타입 모델링
    • TypeScript가 타입을 추론하도록 두는 경우와 타입을 직접 작성하는 경우는 각각 언제 알맞을까요? 여러 타입 들어갈 수 있을 땐 추론 ㄱㄱ or 같은 함수 이름에 다른 타입 입력 필요할 때 확실하게 타입 명시하면 코드 읽을 때 편함
    • 객체와 함수의 형태를 타입으로 표현하면 어떤 실수를 미리 찾을 수 있을까요? 포멧이나 오타 잡기 ㄱㄴ
    • type과 interface는 표현 범위와 확장 방식에서 어떤 차이가 있을까요? type은 &로 합치면 never 되고 오류가 안남 interface는 오류나서 바로 고치기 ㄱㄴ
  • 유니언 타입과 타입 좁히기
    • 여러 타입 중 하나가 될 수 있는 값을 유니언 타입으로 표현하면 어떤 장점이 있나요? 오타 방지
    • 조건문, typeof와 판별 프로퍼티는 타입을 어떻게 좁히나요? 그 scope 안에 어떤 타입 들어가는 지 자동으로 잡아줌 판별 union으로 특정 상황에서만 나오는 key를 나눠서 설정 ㄱㄴ
    • null과 undefined가 포함된 값을 안전하게 다룰 때 옵셔널 체이닝과 널 병합 연산자는 어떤 역할을 하나요? ?. ⇒ 없으면 undefined로 해줌 ??나 ||로 없으면 값 어떻게 채울 지 명시 가능. ??가 null이나 undefined일 때만 처리하므로, ?? 추천. ||는 falsy
  • 타입 안전성과 제네릭
    • any와 unknown은 타입 검사를 허용하는 방식이 어떻게 다른가요? any는 타입 검사를 끔 unknown은 밑에 typeof로 내부 scope에서 타입 조건 가능
    • 여러 타입을 받을 때 unknown과 제네릭은 각각 어떤 상황에 알맞을까요? unknown은 받고 typeof 검사 ⇒ 외부에서 데이터 가져올 때 generic은 타입 기억. 즉, 들어올 때부터 검사 ⇒ 근데 꼭 입력에 그 Type을 안 받아도 됨. function arg에 타입을 받을 수가 없어서 Generic으로 type 받기. function tmp(): t 로 tmp ⇒ return을 string으로 받기 가능
    • 제네릭은 입력 타입과 출력 타입의 관계를 어떻게 유지하나요? 입력 타입을 살림. python에선 그냥 살려주지만, ts는 타입 명시 필요. any는 타입을 없애버려서 문제기 때문에 제너릭으로 타입 살리기

0개의 댓글