woowacourse-study / 2022-thanks-giving-effective-typescript

๐Ÿ‚์ถ”์„ ์—ฐํœด ์ง‘์ค‘๐Ÿ‚ ์ดํŽ™ํ‹ฐ๋ธŒ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ฝ๋Š” ๋ชจ์ž„ (โœŒ๏ธ์™„์ฃผ์™„๋ฃŒโœŒ๏ธ)
6 stars 0 forks source link

2022.09.11 #8

Closed moonheekim0118 closed 2 years ago

moonheekim0118 commented 2 years ago

image ์˜์ฐจ ์˜์ฐจ ๐ŸŒ

prefer2 commented 2 years ago

ํ•˜๋‚˜ ๋‘˜ ๐ŸŒ ํ•˜๋‚˜ ๋‘˜ ๐ŸŒ (๋‚˜๋ฆ„ ์ „๋ ฅ์งˆ์ฃผ ์ค‘)

์œ ๋‹ˆ์˜จ์˜ ์ธํ„ฐํŽ˜์ด์Šค๋ณด๋‹ค๋Š” ์ธํ„ฐํŽ˜์ด์Šค์˜ ์œ ๋‹ˆ์˜จ์„ ์‚ฌ์šฉํ•˜๊ธฐ

interface Crew {
  name: SophiaName | SellyName | HopeName;
  emoji: SophiaEmoji | SellyEmoji | HopeEmoji;
}

name์ด SophiaName์ด๋ฉด์„œ emoji๊ฐ€ SellyEmoji์ผ ์ˆ˜๋Š” ์—†๋‹ค. ์ด๋Ÿฐ ์กฐํ•ฉ์„ ํ—ˆ์šฉํ•˜๋ฉด ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ์‰ฝ๊ณ  ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋‹ค๋ฃจ๊ธฐ ์–ด๋ ค์›Œ์ง„๋‹ค โ†’ ๊ฐ๊ฐ์˜ ํƒ€์ž…์˜ ๊ณ„์ธต์„ ๋ถ„๋ฆฌ๋œ ์ธํ„ฐํŽ˜์ด์Šค๋กœ ๋‘์ž

interface SophiaCrew {
  name: SophiaName;
  emoji: SophiaEmoji
}

์ด๋Ÿฐ ํ˜•ํƒœ๋กœ ์ •์˜ํ•˜๋ฉด ์†์„ฑ์ด ์ž˜๋ชป๋œ ์กฐํ•ฉ์œผ๋กœ ์„ž์ด๋Š” ๊ฒฝ์šฐ๋ฅผ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค.

ํƒœ๊ทธ๋œ ์œ ๋‹ˆ์˜จ ์‚ฌ์šฉํ•˜๊ธฐ. type์ด๋ผ๋Š” ํ•„๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ๊ตฌ๋ถ„ํ•˜๊ธฐ. ํƒœ๊ทธ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ๋Ÿฐํƒ€์ž„์— ์–ด๋–ค ํƒ€์ž…์ด ์‚ฌ์šฉ๋˜๋Š”์ง€ ํŒ๋‹จํ•  ๋•Œ ์‚ฌ์šฉ๋œ๋‹ค. ์ด๋Ÿฌ๋ฉด ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์ฝ”๋“œ์˜ ์ •ํ™•์„ฑ์„ ์ฒดํฌํ•˜๋Š”๋ฐ ๋„์›€์ด ๋œ๋‹ค.

interface SophiaCrew {
  type: 'sohpia'
  name: SophiaName;
  emoji: SophiaEmoji
}

interface SellyCrew {
  type: 'selly'
  name: SellyName;
  emoji: SellyEmoji
}

interface HopeCrew {
  type: 'hope'
  name: HopeName;
  emoji: HopeEmoji
}

type Crew = SophiaCrew | SellyCrew | HopeCrew;

์—ฌ๋Ÿฌ๊ฐœ์˜ ์„ ํƒ์  ํ•„๋“œ๊ฐ€ ๋™์‹œ์— ๊ฐ’์ด ์žˆ๊ฑฐ๋‚˜ ๋™์‹œ์— undefined์ธ ๊ฒฝ์šฐ, ๋‘๊ฐœ์˜ ์†์„ฑ์„ ํ•˜๋‚˜์˜ ๊ฐ์ฒด๋กœ ๋ชจ์œผ๋Š” ๊ฒƒ์ด ๋” ์ข‹์€ ์„ค๊ณ„์ด๋‹ค.

interface Person {
  name: string;
  // ๋‘ ๊ฐ’์ด ๋™์‹œ์— ์žˆ๊ฑฐ๋‚˜ ์—†์–ด์•ผ ํ•œ๋‹ค
  placeOfBirth?: string;
  dateOfBirth?: Date;
}

interface Person {
  name: string;
  birth?: {
    place: string;
    date: Date;
  }
}

API์˜ ๊ฒฐ๊ณผ์™€ ๊ฐ™์ด ํƒ€์ž…์˜ ๊ตฌ์กฐ๋ฅผ ์† ๋Œˆ ์ˆ˜ ์—†๋Š” ์ƒํ™ฉ์ด๋ฉด ์ธํ„ฐํŽ˜์ด์Šค์˜ ์œ ๋‹ˆ์˜จ์„ ์‚ฌ์šฉํ•ด์„œ ์†์„ฑ ์‚ฌ์ด์˜ ๊ด€๊ณ„๋ฅผ ๋ชจ๋ธ๋งํ•˜์ž.

string ํƒ€์ž…๋ณด๋‹ค ๋” ๊ตฌ์ฒด์ ์ธ ํƒ€์ž… ์‚ฌ์šฉํ•˜๊ธฐ

string ํƒ€์ž…์˜ ๋ฒ”์œ„๋Š” ๋งค์šฐ ๋„“๋‹ค. ๋ณ€์ˆ˜์˜ ๋ฒ”์œ„๋ฅผ ์ •ํ™•ํ•˜๊ฒŒ ํ‘œํ˜„ํ•˜๊ณ ์ž ํ•œ๋‹ค๋ฉด string ํƒ€์ž…๋ณด๋‹ค๋Š” ๋ฌธ์ž์—ด ๋ฆฌํ„ฐ๋Ÿด์˜ ์œ ๋‹ˆ์˜จ์„ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.

function pluc(records: any[], key: string): any[] {
  return records.map(r => r[key]);
}

// any๊ฐ€ ์žˆ์–ด ์ข‹์ง€ ์•Š๋‹ค. generic์„ ๋„์ž…ํ•ด๋ณด์ž

function pluc2<T>(records: T[], key: string): any[] {
  return records.map(r => r[key]);
  // Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'unknown'.
  // No index signature with a parameter of type 'string' was found on type 'unknown'.
}

// key์˜ ํƒ€์ž…์ด string์ด๋ผ ๋ฒ”์œ„๊ฐ€ ๋„ˆ๋ฌด ๋„“๋‹ค
// ๊ฐ์ฒด์˜ ์†์„ฑ ์ด๋ฆ„์„ ํ•จ์ˆ˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ฐ›์„ ๋•Œ๋Š” keyof T๋ฅผ ์‚ฌ์šฉํ•˜์ž
function pluc3<T>( records: T[], key: keyof T){
  return records.map(r => r[key]);
}

// ๋ฒ”์œ„๋ฅผ ๋” ์ขํžˆ๊ธฐ ์œ„ํ•ด์„œ keyof T์˜ ๋ถ€๋ถ„์ง‘ํ•ฉ์„ ๋„์ž…ํ•˜์ž
// string ๋Œ€์‹  keyof๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ž๋™์™„์„ฑ ๊ธฐ๋Šฅ๋„ ๊ฐœ์„ ๋œ๋‹ค
function pluc4<T, K extends keyof T>( records: T[], key: K): T[K][]{
  return records.map(r => r[key]);
}

๋ถ€์ •ํ™•ํ•œ ํƒ€์ž…๋ณด๋‹ค๋Š” ๋ฏธ์™„์„ฑ ํƒ€์ž…์„ ์‚ฌ์šฉํ•˜๊ธฐ

๋ฐ์ดํ„ฐ๊ฐ€ ์•„๋‹Œ, API์™€ ๋ช…์„ธ๋ฅผ ๋ณด๊ณ  ํƒ€์ž… ๋งŒ๋“ค๊ธฐ

ํ•ด๋‹น ๋ถ„์•ผ์˜ ์šฉ์–ด๋กœ ํƒ€์ž… ์ด๋ฆ„ ์ง“๊ธฐ

๊ณต์‹ ๋ช…์นญ์—๋Š” ์ƒํ‘œ๋ฅผ ๋ถ™์ด๊ธฐ

nominal typing

์ด๋ฆ„์œผ๋กœ ํƒ€์ž…์„ ๊ตฌ๋ถ„ํ•˜๋Š” ๊ฒƒ. C, C++์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹

class A {
    method(input: string): number {...}
}
class B {
    method(input: string): number {...}
}

let a: A = new B(); // Error

ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ Structural ํƒ€์ž…์ธ๋ฐ ์ฝ”๋“œ๋ฅผ ๋”ํ•˜์—ฌ normial์˜ ์ด์ ์„ ๊ฐ€์ ธ๊ฐˆ ์ˆ˜ ์žˆ๋‹ค. _brand( _brand ํ˜•์‹์€ ์ปจ๋ฒค์…˜์ด๋‹ค)๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ๊ฐ’์„ ๊ตฌ๋ถ€ํ•˜๊ธฐ ์œ„ํ•ด ์ƒํ‘œ๋ฅผ ๋ถ™์ด๋Š” ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด ์ข‹๋‹ค.

type ValidatedInputString = string & { __brand: "User Input Post Validation"}; // stringํƒ€์ž…์— ์ƒํ‘œ ๋ถ™์ด๊ธฐ

// ์ œ์•ฝ ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋Š” ๋ฌธ์ž์—ด๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜
const validateUserInput = (input: string) => {
    const simpleValidatedInput = input.replace(/\</g, "<=");
    return simpleValidatedInput as ValidatedInputString;
};

// ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋Š” ๋ฌธ์ž์—ด๋งŒ ๋ฐ›์•„ ์ถœ๋ ฅํ•˜๋Š” ํ•จ์ˆ˜
const printName = (name: ValidatedInputString) => {
    console.log(name);
}

type Meters = number & {_brand: 'meters'} // numberํƒ€์ž…์— ์ƒํ‘œ ๋ถ™์ด๊ธฐ
// brand๋ฅผ ๋ถ™์—ฌ๋„ ์‚ฐ์ˆ  ์—ฐ์‚ฐ ํ›„์—๋Š” ์—†์–ด์ง€๊ธฐ ๋•Œ๋ฌธ์— ์‚ฌ์šฉํ•˜๊ธฐ์— ๋ฌธ๋ฆฌ๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ๋‹ค

์ฐธ๊ณ 

https://www.typescriptlang.org/play#example/nominal-typing

liswktjs commented 2 years ago

๋“œ๋””์–ด 3์žฅ ํƒˆ์ถœ๐ŸŒ

ํƒ€์ž… ์ถ”๋ก ์— ๋ฌธ๋งฅ์ด ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉ๋˜๋Š”์ง€ ์ดํ•ดํ•˜๊ธฐ

type Language = 'Javascript' | 'Typescript' | 'Python';
function setLanguage(language: Language){ } 

setLanguage('Javascript')  // ์ •์ƒ 

let language = 'Javascript';
setLanguage(language); // string ํ˜•์‹์˜ ์ธ์ˆ˜๋Š” 'Language'ํ˜•์‹์˜ ๋งค๊ฐœ๋ณ€์ˆ˜์— ํ• ๋‹น ํ•   ์ˆ˜ ์—†์Œ

ํ•จ์ˆ˜ํ˜• ๊ธฐ๋ฒ•๊ณผ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ ํƒ€์ž… ํ๋ฆ„ ์œ ์ง€ํ•˜๊ธฐ

ํƒ€์ž… ์„ค๊ณ„

์œ ํšจํ•œ ์ƒํƒœ๋งŒ ํ‘œํ˜„ํ•˜๋Š” ํƒ€์ž… ์ง€ํ–ฅํ•˜๊ธฐ

interface State {
    pageText: string;
    isLoading: boolean;
    error ?: string;
} 

function renderPage(state: State){
    if(state.error){
        return `Error`
  } else if (state.isLoading){
        return 'Loading';
    } 
    return `ใ„ดใ„ดใ„ดใ„ด`
} -> isLoading์ด true์ด๊ณ  error๊ฐ€ ์กด์žฌํ•  ๊ฒฝ์šฐ์— ๋Œ€ํ•ด์„œ ๋กœ๋”ฉ ์ค‘์ธ ์ƒํƒœ์ธ์ง€ ์—๋Ÿฌ ์ƒํƒœ์ธ์ง€ ๋ช…ํ™•ํ•˜๊ฒŒ 
๊ตฌ๋ถ„์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค 
async function changePage(state: State, newPage: string){
    state.isLoading = true;
    try {
        const response = await fetch(getUrlForPage(newPage));
        if(!response.ok){
            throw new Error(`unable to load`); -> ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ์—, isLoading์ด false๋กœ
            ๋˜๋Š” ๋กœ์ง ๋ถ€์žฌ 
            -> state.error๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜์ง€ ์•Š์•„ ๊ณผ๊ฑฐ์˜ ์˜ค๋ฅ˜ ๋ฉ”์„ธ์ง€๊ฐ€ ๋ณด์—ฌ์งˆ ์ˆ˜ ์žˆ๋‹ค 
        }
        const text = await response.text();
        state.isLoading = false;
        state.pageText = text;
    } catch (e) {
        state.error = ' ' | e;
    }
}

-> ํŽ˜์ด์ง€ ๋กœ๋”ฉ ์ค‘์— ์‚ฌ์šฉ์ž์˜ ํŽ˜์ด์ง€๊ฐ€ ๋ฐ”๋€Œ์–ด ๋ฒ„๋ฆฌ๋ฉด, ์–ด๋–ค ์ผ์ด ๋ฐœ์ƒํ• ์ง€ ์˜ˆ์ƒํ•˜๊ธฐ ์–ด๋ ต๋‹ค. 
interface RequestPending {
    state: 'pending';
}

interface RequestError {
    state: 'error';
    error: string;
}

interface RequestSuccess {
    state: 'ok';
    pageText: string;
}

type RequestState = RequestPending | RequestError | RequestSuccess; 

์‚ฌ์šฉํ•  ๋•Œ๋Š” ๋„ˆ๊ทธ๋Ÿฝ๊ฒŒ, ์ƒ์„ฑํ•  ๋•Œ๋Š” ์—„๊ฒฉํ•˜๊ฒŒ

moonheekim0118 commented 2 years ago

๋ถ€์ •ํ™•ํ•œ ํƒ€์ž…๋ณด๋‹ค๋Š” ๋ฏธ์™„์„ฑ์˜ ํƒ€์ž… ์‚ฌ์šฉํ•˜๊ธฐ

๋ฐ์ดํ„ฐ๊ฐ€ ์•„๋‹Œ, API ์™€ ๋ช…์„ธ๋ฅผ ๋ณด๊ณ  ํƒ€์ž… ๋งŒ๋“ค๊ธฐ

ํ•ด๋‹น๋ถ„์•ผ์˜ ์šฉ์–ด๋กœ ํƒ€์ž… ์ด๋ฆ„ ์ง“๊ธฐ

๊ณต์‹ ๋ช…์นญ์—๋Š” ์ƒํ‘œ๋ฅผ ๋ถ™์ด๊ธฐ

interface Vector2D{
  x: number;
  y: number;
}

function calculateNorm(p:Vector2D){}

const vec3D = {x: 3, y:4, z:1};
calculateNorm(vec3D); // ์ •์ƒ!!
interface Vector2D{
  _brand:'2D';
  x: number;
  y: number;
}

function calculateNorm(p:Vector2D){}

const vec3D = {x: 3, y:4, z:1};
calculateNorm(vec3D); // _brand ์†์„ฑ์ด ํ˜•์‹์— ์—†์Šต๋‹ˆ๋‹ค.
type AbsoultePath = string & {_brand:'abs'};

function listAbsolutePath(path: AbsoultePath){
  // ..
}

function isAbsolutePath(path:string): path is AbsoultePath{
   return path.startsWith('/');
}

function f(path:string){
    if(isAbsolutePath(path)){
        listAbsolutePath(path);
    }
    listAbsolutePath(path); // error 
}

any ํƒ€์ž…์€ ๊ฐ€๋Šฅํ•œ ํ•œ ์ข์€ ๋ฒ”์œ„์—์„œ๋งŒ ์‚ฌ์šฉํ•˜๊ธฐ


type Bar = 'example';
function processBar(b:Bar){}

function f1(){
    const x: any = 'foo';
    processBar(x); // ์ด๋ ‡๊ฒŒ ํ•˜์ง€๋งˆ์‹œ์˜ค
}

function f2(){
    const x= 'foo';
    processBar(x as any); // ์ด๊ฒŒ ๋‚ซ๋‹ค.
}
soyi47 commented 2 years ago

์นจ์ฐฉํ•ด. ๋„ค๊ฐ€ ๊ฐ€์•ผํ•  ๊ณณ์—๋งŒ ์ง‘์ค‘ํ•ด์•ผ ํ•ด. ๐ŸŒ๐ŸŒ๐ŸŒ

์•„์ดํ…œ 31. ํƒ€์ž… ์ฃผ๋ณ€์— null ๊ฐ’ ๋ฐฐ์น˜ํ•˜๊ธฐ

์•„์ดํ…œ 32. ์œ ๋‹ˆ์˜จ์˜ ์ธํ„ฐํŽ˜์ด์Šค๋ณด๋‹ค๋Š” ์ธํ„ฐํŽ˜์ด์Šค์˜ ์œ ๋‹ˆ์˜จ์„ ์‚ฌ์šฉํ•˜๊ธฐ

์•„์ดํ…œ 33. string ํƒ€์ž…๋ณด๋‹ค ๋” ๊ตฌ์ฒด์ ์ธ ํƒ€์ž… ์‚ฌ์šฉํ•˜๊ธฐ

string ํƒ€์ž…๋ณด๋‹ค ๋” ๊ตฌ์ฒด์ ์ธ ํƒ€์ž…์„ ์‚ฌ์šฉํ•˜๋ฉด ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋Š” ์˜ค๋ฅ˜๋ฅผ ๋” ์ž˜ ์ฒดํฌํ•  ์ˆ˜ ์žˆ๋‹ค.

์•„์ดํ…œ 34. ๋ถ€์ •ํ™•ํ•œ ํƒ€์ž…๋ณด๋‹ค๋Š” ๋ฏธ์™„์„ฑ ํƒ€์ž…์„ ์‚ฌ์šฉํ•˜๊ธฐ

์•„์ดํ…œ 35. ๋ฐ์ดํ„ฐ๊ฐ€ ์•„๋‹Œ, API์™€ ๋ช…์„ธ๋ฅผ ๋ณด๊ณ  ํƒ€์ž… ๋งŒ๋“ค๊ธฐ

์˜ˆ์‹œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฐธ๊ณ ํ•ด ํƒ€์ž…์„ ์ƒ์„ฑํ•˜๋ฉด ๋ณด์ด๋Š” ๋ฐ์ดํ„ฐ๋งŒ ๊ณ ๋ คํ•˜๊ฒŒ ๋˜๋ฏ€๋กœ ์˜ˆ๊ธฐ์น˜ ์•Š์€ ๊ณณ์—์„œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค. ๋ช…์„ธ๋ฅผ ์ฐธ๊ณ ํ•ด ํƒ€์ž…์„ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

์•„์ดํ…œ 36. ํ•ด๋‹น ๋ถ„์•ผ์˜ ์šฉ์–ด๋กœ ํƒ€์ž… ์ด๋ฆ„ ์ง“๊ธฐ

์•„์ดํ…œ 37. ๊ณต์‹ ๋ช…์นญ์—๋Š” ์ƒํ‘œ๋ฅผ ๋ถ™์ด๊ธฐ