Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[4장] 타입 설계 (아이템 28 ~ 아이템 37) #6

Open
dahye1013 opened this issue Sep 27, 2022 · 27 comments
Open

[4장] 타입 설계 (아이템 28 ~ 아이템 37) #6

dahye1013 opened this issue Sep 27, 2022 · 27 comments
Labels

Comments

@dahye1013
Copy link
Member

[4장 퀴즈]

타입 추론 타입 설계 (아이템 28 ~ 아이템 37)

아래 마크다운을 복사 붙여넣기해서 코멘트로 퀴즈를 달아주세요 :)
객관식, 주관식에 상관없이 편하게 만들어주세요!

부가 설명을 달고 싶다면, 해설을 정답과 함께 옵션으로 작성하시면 됩니다. ☺️

예시

### 아이템 N

퀴즈 내용 객관식의 정답을 골라보세요!
(퀴즈 내용)

1. 1번
2. 2번
3. 3번

<details>
<summary>퀴즈 정답</summary>
<div markdown="1">    
정답은 1번!
</div>
</details>
@dahye1013 dahye1013 added the 4장 label Sep 27, 2022
@tooooo1
Copy link
Contributor

tooooo1 commented Oct 1, 2022

아이템 32

interface Layer {
  layout : FillLayout | LineLayout;
  paint: FillPaint | LinePaint;
}

 같이 설계하는 것보다  나은 설계방법은 무엇일까요?
그리고   나을까요?
퀴즈 정답
interface FillLayer와 LineLayer를 만들고 type Layer에 유니온으로 묶어주는방식이 더 나은 설계방식이다. 해당 방식으로 Layer를 정의하면 잘못된 조합으로 섞이는 경우를 방지할 수 있어서 더 유리하다.

@tooooo1
Copy link
Contributor

tooooo1 commented Oct 1, 2022

아이템 33

string 타입은 생각보다 넓은 타입입니다.
color를 설정할 때, 검은색과 하얀색만 받는다면 어떻게 좁힐 수 있을까요? 또한 좁혀야하는 이유는 무엇일까요?

퀴즈 정답
type color = 'black' | 'white';

위와 같이 구체적으로 string을 좁히면 다른 틀린 값들이 들어오는 실수를 방지할 수 있다.

@tooooo1
Copy link
Contributor

tooooo1 commented Oct 1, 2022

아이템 35

API에 대해 타입 정의 시, 데이터를 보고 타입을 정의하는게 바람직할까요? 명세를 보고 타입을 정의하는게 바람직할까요?

선택하셨다면 그 이유에 대해 설명해주세요!

퀴즈 정답
데이터가 아닌 명세를 보고 타입을 만들어야 한다. 데이터를 보고 타입을 정의하면 눈앞에 있는 데이터만 고려하게 되므로 예기치 않은 곳에서 오류가 발생할 수 있다. 데이터에 드러나지 않는 예외적인 경우들도 고려해주자!

@MINGDY98
Copy link

MINGDY98 commented Oct 2, 2022

아이템30

동료 개발자와 원활한 협업을 위해 타입 정보들은 모두 주석으로 남겨주는 것이 좋다.(O/X)

퀴즈 정답
X

주석으로된 타입 정보에 모순이 발생할 수 있고 충분히 타입 정보를 코드로 남길 수 있다.
그러나 만약 단위가 있는 숫자가 타입이 명확하지 않은 경우에는 단위 정보를 변수명에 포함하는 것을 고려하는 것이 좋다.
ex) timeMs가 time 보다 훨씬 명확하다.

@MINGDY98
Copy link

MINGDY98 commented Oct 2, 2022

아이템 31

다음 중 맞는 설명을 모두 고르시오.

  1. 한 값의 null 여부가 다른 값의 null 여부에 관련되도록 설계해도 관계 없다.
  2. API 작성 시에는 반환 타입을 큰 객체로 만들고 반환 타입 전체가 null이거나 null이 아니게 만들어야한다. 사람과 타입 체커 모두에게 명료한 코드가 될 것이다.
  3. 클래스를 만들 때는 null이 존재하도록 하는 것이 좋다.
  4. stricNullChecks를 설정하면 코드에 많은 오류가 표시되고, null값과 관련된 문제점을 찾아낼 수 있기 때문에 반드시 필요하다.
퀴즈 정답
2,4 번

@MINGDY98
Copy link

MINGDY98 commented Oct 2, 2022

아이템 34

string 타입으로만 남발하여 선언된 코드를 피하는 것이 좋다.(O/X)

퀴즈 정답
정답은 O

string 타입보다는 더 구체적인 타입을 사용하는 것이 좋다.

ex)

1.
inteface Album {
  artist: string;
  title : string;
  releaseDate : string;
  recordingType: string;
}

2.
type RecordingType = 'studio'|'live';
interface Album {
  artist: string;
  title: string; 
  releaseDate: Date;
  recording Type: RecordingType;
}

2번처럼 코드를 작성하면, 타입스크립트는 오류를  세밀하게 체크할  있다.

@areumsheep
Copy link
Member

areumsheep commented Oct 2, 2022

아이템 30

당신은 회사의 코드를 유지보수 해야 합니다.
아래 코드는 어떤 식으로 수정하는 것이 좋을까요?

/** 매개변수로 받은 arr은 변경되지 않습니다. */
function concat(arr: string[]) {
  //...
}
퀴즈 정답

정답은 주석보단 readonly로 선언하여 타입스크립트가 규칙을 강제할 수 있도록 하면 됩니다.

function concat(arr: readonly string[]) {
  //...
}

@areumsheep
Copy link
Member

areumsheep commented Oct 2, 2022

아이템 33

당신은 회사의 코드를 유지보수 해야 합니다.
아래 코드는 어떤 식으로 수정하는 것이 좋을까요?

단, subject에는 math, english, korean만 들어갈 수 있습니다.
grade에는 A, B, C, D, E만 들어갈 수 있습니다.

function calculate(subject: string, grade: string) {
  //...
}
퀴즈 정답

string을 제거하고 유니온 타입을 사용해 받을 수 있는 값을 지정해주는 것이 좋습니다.
지정해줄 경우 아래의 세 가지 이점을 가질 수 있습니다.

  1. 다른 곳으로 값이 전달되어도 타입 정보가 유지된다.
  2. 타입을 명시적으로 정의하고 해당 타입의 의미를 설명하는 주석을 넣을 수 있다.
  3. keyof 연산자로 더욱 세밀하게 객체의 속성 체크를 할 수 있다.

정답은 아래와 같습니다. (* 더 좋은 방안이 있다면 알려주세요)

type Subject = 'math' | 'english' | 'korean';
type Grade = 'A' | 'B' | 'C' | 'D' | 'E';

function calculate(subject: Subject, grade: Grade) {
  //...
}

@areumsheep
Copy link
Member

areumsheep commented Oct 2, 2022

아이템 37

빈 칸 안에 들어갈 말은?

구조적 타입 시스템을 지원하는 타입스크립트에서 ㅁㅁ를 붙여 명시적 타입 시스템처럼 검사할 수 있다.

퀴즈 정답

정답은 상표 입니다!

type Meters = number & {_brand: 'meters'}; //_brand: 'meters'
type Seconds = number & {_brand: 'seconds'}; //_brand: 'seconds'

const meters = (m: number) => m as Meters;
const seconds = (s: number) => s as Seconds;

const oneKm = meters(1000);
const oneMin = seconds(60);

@seojihwan
Copy link

seojihwan commented Oct 3, 2022

아이템 28

다음의 타입스크립트 코드의 문제점은?

interface State {
  loading: boolean
  error?: Error
}
퀴즈 정답

로딩상태이면서, error인 상태가 존재할 수 없지만 타입상으로 존재함
유니온 타입으로 개선해보자

  type State = RequestSuccess | RequestPending | RequestFailed

  interface RequestSuccess {
    loading: false
  }

  interface RequestPending {
    loading: true
  }

  interface RequestFailed {
    loading: false
    error: Error
  }

@seojihwan
Copy link

아이템 30

다음 코드의 아쉬운점은?

  function delay(time: number){
    ... // 일정시간의 딜레이를 줌
  }
퀴즈 정답 내부 구현을 들여다 보지 않고서는, time의 단위가 얼마인지 알 수없음 ```ts function delay(ms: number){ ... // 일정시간의 딜레이를 줌 } ``` 변수명을 타입과 함께 잡숴보세요.

@seojihwan
Copy link

아이템 33

  interface Album {
    artist: string;
    title: string;
    releaseDate: Date;
    recordingType: 'studio' | 'live'
  }

  function pluck<T>(records: T[], key: keyof T): T[keyof T][] {
    return records.map(r => r[key]);
  }

  pluck(albums, 'releaseDate') // 여기서 추론되는 타입은?
퀴즈 정답 (string | Date)[] keyof T의 타입이 "artist" | "title" | "releaseDate" | "recordingType" 으로 추론되기 때문이다. key의 타입이 'releaseDate'로 추론되도록 generic을 활용해보자. ```ts function pluck(records: T[], key: K): T[K][] { return records.map(r => r[key]); }
pluck(albums, 'releaseDate') // Date[]
</details>

@dahye1013
Copy link
Member Author

아이템 37

'상표 기법' 에 대한 특징으로 옳지 않은 것은?

  1. 타입 시스템에서 동작합니다.
  2. 런타임에서 검사하는 것과 동일한 효과를 얻습니다.
  3. 런타임 오버헤드를 없앨 수 있습니다.
  4. 추가 속성을 붙일 수 없는 내장 타입에는 상표화할 수 없습니다.
퀴즈 정답
4번은 옳지 않습니다.

추가 속성을 붙일 수 없는 string, number 내장 타입도 상표화가 가능합니다!

@dahye1013
Copy link
Member Author

아이템 33

keyof 를 사용하면 세밀하게 객체의 속성 체크가 가능해집니다.
주어진 타입 keyof를 활용하여, pluck 함수의 타입을 좁혀보세요!

type RecordingType = 'studio' | 'live';
interface Album {
    artist: string;
    title: string;
    releaseDate: Date;
    recordingType: RecordingType;
}
function pluck<T>(records: T[], key:string): any {
    return records.map(r => r[key]);
}
퀴즈 정답

Playground Link

type RecordingType = 'studio' | 'live';
interface Album {
    artist: string;
    title: string;
    releaseDate: Date;
    recordingType: RecordingType
}

function pluck<T, K extends keyof T>(records: T[], key: K) : T[K][] {
    return records.map(r => r[key]);
}

@dahye1013
Copy link
Member Author

아이템 31

하단의 코드를 타입에러가 나는 코드입니다.
(1). 어떤 타입에러가 발생하는이 추론해보세요
(2). let min, max 를 null이 타입추론이 가능하도록 수정하여 에러를 수정해보세요.

function extent(nums: number[]) {
    let min, max;
    for(const num of nums) {
        if(!min) {
            min = num;
            max = num;
        } else {
            min = Math.min(min, num);
            max = Math.max(max, min);
        }
    }
    return [min, max]
}
퀴즈 정답

(1) extent의 반환타입이 (number | undefined)[]로 추론되어 아래와 같은 에러가 발생합니다.
Argument of type 'number | undefined' is not assignable to parameter of type 'number'. Type 'undefined' is not assignable to type 'number'.(2345)

(2)

function extent(nums: number[]) {
    let result: [number, number] | null = null;
    for(const num of nums) {
        if(!result) {
            result = [num, num];
        } else {
            result = [Math.min(num, result[0]), Math.max(num, result[1])];
        }
    }
    return result;
}

@jlee0505
Copy link
Member

jlee0505 commented Oct 3, 2022

아이템 28

아래 코드와 같은 타입 디자인으로 가장 적절한 것은?

interface RequestPending {
 state: 'pending';
}
interface RequestError {
 state: 'error';
 error: string;
}
interface RequestSuccess {
 state: 'ok';
 pageText: string;
}
type RequestState = RequestPending | RequestError | RequestSuccess;
interface State {
 currentPage: string;
 requests: {[page: string]: RequestState};
}
  1. Prefer Unions of Interfaces to Interfaces of Unions
  2. Discriminate Union
  3. DRY(Don’t Repeat Type Information in Documentation)
퀴즈 정답
정답은 2번!

@jlee0505
Copy link
Member

jlee0505 commented Oct 3, 2022

아이템 29-30

다음중 권장되는 type design 이 아닌 특성을 고르시오.
(퀴즈 내용)

  1. Input types tend to be broader than output types
  2. Avoid repeating type information in comments and variable names
  3. Optional properties and union types are more common in parameter types than return types
  4. Consider excluding units in variable names because it only adds confusion (e.g. timeMs -> time)
퀴즈 정답
정답은 4번! Consider including units in variable names for clarity.

@jlee0505
Copy link
Member

jlee0505 commented Oct 3, 2022

아이템 31

What would be the bugs you could find in the below example?

function extent(nums: number[]) {
 let min, max;
 for (const num of nums) {
 if (!min) {
 min = num;
 max = num;
 } else {
 min = Math.min(min, num);
 max = Math.max(max, num);
 }
 }
 return [min, max];
}
퀴즈 정답
Answer: 1. If the min or max is zero, it may get overridden. 2. If the nums array is empty, the function will return [undefined, undefined].

@yeomgahui
Copy link

아이템 28

유효한 상태와 무효한 상태를 둘 다 표현하는 타입은 혼란을 초래하기 쉽고 오류들을 유발합니다. 다음 interface를 적절하게 고쳐주세요.

interface State { pageText: string; isLoading: boolean; error?: string; }
퀴즈 정답 ```TS interface RequestPending { state:'Pending'; } interface RequestError { state: 'Error'; error: string; } interface RequestSuccess { state: 'ok'; pageText: string; } type RequestState = RequestPending | RequestError | RequestSuccess; ```

@yeomgahui
Copy link

아이템 29

매개변수와 반환 타입의 재사용을 위해서 기본 형태와 느슨한 형태를 도입하는 것이 좋다. (O/X)

퀴즈 정답
O 보통 매개변수 타입은 반환 타입에 비해 범위가 넓은 경향이 있다. 그러므로 느슨한 형태를 도입하는 것이 좋다.

@yeomgahui
Copy link

아이템 31

null 값과 관련된 문제점을 찾아낼 수 있기 때문에 반드시 필요한 tsconfig 속성은 무엇일까요?

퀴즈 정답
strictNullChecks

@sooooo-an
Copy link

아이템 32

이 코드를 인터페이스 유니온을 사용하여 개선해보세요

interface Animal {
	type: 'dog' | 'cat' | 'rabbit'
	name: 'dog' | 'cat' | 'rabbit'
}

function logName(animal: Animal){
	if(animal.type === 'dog'){
		animal.name // 'dog' | 'cat' | 'rabbit'
	}
} 
퀴즈 정답
``` type Animal = Dog | Cat | Rabbit

interface Dog {
type: 'dog'
name: 'dog'
}

interface Cat {
type: 'cat'
name: 'cat'
}

interface Rabbit {
type: 'rabbit'
name: 'rabbit'
}

function logName(animal: Animal){
if(animal.type === 'dog'){
animal.name // 'dog'
}
}

</div>
</details>

@sooooo-an
Copy link

아이템 33

구체적인 타입으로 변경하세요

function pluck<T>(records: T[], key: **keyof T**): T[keyof T][] {
	return records.map(r => r[key]);
}
퀴즈 정답
``` function pluck(records: T[], key: K): T[K][] { return records.map(r => r[key]); } ```

@sooooo-an
Copy link

아이템 36

name의 이름이 적절한 것을 고르세요

interface Animal {
	name: string;
}
  1. animalName
  2. 'name`
퀴즈 정답
정답은 1번!

@parksil0
Copy link

아이템 30

아래의 코드를 보고 주석을 제거하기 위해 좋은 방안은?

/**  nums를 변경하지 않습니다. */
function sort(num: number[]) {
  //...
 }
퀴즈 정답
매개변수 num에 readonly를 붙인다.

@parksil0
Copy link

아이템 31

아래의 코드의 리턴 타입이 any[]인 이유는?

function extent(nums: number[]) {
  let max, min;
  for (const num of nums) {
    if (!min) {
      min = num;
      max = num;
    } else {
      min = Math.min(min, num);
      max = Math.max(max, num);
    }
  }

  return [min, max];
}
퀴즈 정답
변수 num의 null check가 안 되었기 때문이다. null check를 하고나서 배열에 담아야 number[]타입을 리턴한다.

@parksil0
Copy link

아이템 36

아래의 타입에서 애매한 부분을 고쳐보시오.

interface Person {
  type: 'a' | 'b' | 'o' | 'ab';
  size: 's' | 'm' | 'l' | 'xl'; // 상의 사이즈
  name1: string; // 이름
  name2: string; // 닉네임
}
퀴즈 정답
type은 bloodType으로, size는 shirtSize로, name1은 name으로, name2는 nickname으로 변경한다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

9 participants