일반적인 타입들은 정제되기만 하는 반면 (ex. 타입 좁히기), 암시적 any와 any[] 타입은 진화할 수 있습니다. 이러한 동작이 발생하는 코드를 인지하고 이해할 수 있어야합니다.
any를 진화시키는 방식보다 명시적 타입 구문을 사용하는 것이 안전한 타입을 유지하는 방법 입니다.
1. 일반적인타입들은정제되기만하는반면,암시적any와any[]타입은진화할수있습니다.
❗️타입의 진화는 값을 할당하거나 배열의 요소를 넣은 ‘후’에만 일어나기 때문에, 편집기에서는 할당 다음 줄을 봐야 진화된 타입이 잡힌다.
//1. 배열의 any 타입 진화(evolve)
const result = []; //any[]
result.push('a');
result //string[]
result.push(1);
result //(string | number)[]
//2. 조건문에 따른 any 타입 진화(evolve)
let val; //any
if(Math.random() < 0.5) {
val = /hello/;
val //RegExp
} else {
val = 12;
val //number
}
val //number | RegExp
//3. 초깃값이 null 인 경우 any 타입 진화(evolve)
let tmp = null; //any
try {
somethingDangerous();
tmp = 12;
tmp //number
} catch (e) {
console.log('err!');
}
tmp //number | null
any 타입의 진화는 "noImplicitAny": true 로 설정된 상태에서 변수의 타입이 암시적 any인 경우에만 일어난다. → 명시적인 경우 진화가 일어나지 않는다.
//명시적인 경우 진화가 일어나지 않는다.
let val2: any; //any
if(Math.random() < 0.5) {
val2 = /hello/;
val2 //any
} else {
val2 = 12;
val2 //any
}
val2 //any
2. any를 진화시키는 방식보다 명시적 타입 구문을 사용하는 것이 안전한 타입을 유지하는 방법이다.
암시적 any 상태인 변수에 어떠한 할당 없이 사용하려 하면 암시적 any 오류가 발생한다.
function range(start: number, limit: number) {
const out = []; //암시적 any
if (start === limit) {
return out; //❌ Error:'out' 변수에는 암시적으로 'any[]' 형식이 포함됩니다.
}
for(let i = start; i < limit; i++) {
out.push(i);
}
return out; // number[] 로 추론되기 때문에 에러 없음.
}
암시적 any 타입은 함수 호출을 거쳐도 진화하지 않는다.
function makeSqure(start: number, limit: number) {
const out = []; //❌ ''out' 변수는 형식을 확인할 수 없는 경우 일부 위치에서 암시적으로 'any[]' 형식입니다.
range(start, limit).forEach(i => {
out.push(i * i);
})
return out;
}
의도치 않은 타입이 섞여서 잘못 진화할 수 있기 때문에, (암시적 any 진화 방식보단) 명시적 타입 구문 사용이 더 좋은 설계다.
const result = []; //any[]
result.push(1);
result //number[]
//보다는 처음부터 명시
const result: number[] = [];
아이템 42모르는타입의값에는any대신unknown을 사용하기
요약
unknown은 any 대신 사용할 수 있는 안전한 타입이다. 어떠한 값이 있지만 그 타입을 알지 못하는 경우라면 unknown을 사용함으로써 타입 단언문이나 타입 체크를 사용하도록 강제할 수 있다. (any 일 때 타입 체크가 안 되는 문제점이 보완된다.)
unknown는 모든 타입의 상위 타입이고, never는 모든 타입의 하위 타입이다. unknown 타입은 모든 타입이 될 수 있으나 모든 타입은 unknown이 될 수 없다. 반대로 never 타입은 모든 타입이 될 수 없고 모든 타입은 never가 될 수 있다.
{} 타입은 null과 undefined를 제외한 모든 값을 포함한다.
1. 어떠한 값이 있지만 그 타입을 알지 못하는 경우라면 any 대신 unknown을 사용하자.
unknown을 사용함으로써 타입 단언문이나 타입 체크를 사용하도록 강제할 수 있다. (any일 때 타입 체크가 안 되는 문제점이 보완된다.)
unknown 은 unknown 인 채로 사용하면 오류가 발생한다.
interface Book {
name: string,
author: string
}
//❌ 반환값이 any 여서 타입 체크가 안되어 런타임 에러가 발생한다.
const parseYamL = (yaml: string): any => {};
const book = parseYamL(`name: Jane
author: Char`);
//parseYamL를 호출한 곳에서 타입 선언이나 타입 단언을 하지 않으면 book이 any가 된다.
//따라서 아래 코드는 타입 에러도 나지 않고 런타임에서 에러가 난다.
console.log(book.title);
book();
//✅ 대신 unknown을 쓰자.
const safetyParseYamL = (text: string): unknown => ({});
const book2 = safetyParseYamL(`name: Jane
author: Char`);
//unknown은 타입에러가 난다! 런타임 단계가 아니라 컴파일 단계에서 에러 확인 가능하다.
console.log(book2.title); // 'book2'은(는) 'unknown' 형식입니다.
book2(); // 'book2'은(는) 'unknown' 형식입니다.
이중 단언문에서도 any 대신 unknown 을 사용할 수도 있다.
declare const foo: Foo;
let barAny = foo as any as Bar;
let barUnk = foo as unknown as Bar;
2. unknown는 모든 타입의 상위 타입이고, never는 모든 타입의 하위 타입이다.
타입의 값을 집합으로 생각하기(아이템7)를 참고해보자.
any 타입은 모든 타입에 할당 될 수도 있고, 모든 타입이 any에 할당 될 수 있으니, 타입 시스템의 열외로 본다. 하지만 unknown은 타입 시스템에 부합한다.
any를 제외한 일반적인 타입은 타입 좁히기(더 작은 집합 되기)만 가능하다. 따라서 unknown 타입은 모든 타입이 될 수 있으나 모든 타입은 unknown이 될 수 없다. 반대로 never 타입은 모든 타입이 될 수 없고 모든 타입은 never가 될 수 있다.
let num: number;
function somethingDo(): unknown {
return;
}
num = somethingDo(); //❌ 'unknown' 형식은 'number' 형식에 할당할 수 없습니다.
function hello(): never {
throw new Error("xxx");
}
num = hello(); //✅
let imNever = hello();
imNever = 12; //❌ 'number' 형식은 'never' 형식에 할당할 수 없습니다
3. {} 타입은 null과 undefined를 제외한 모든 값을 포함한다.
unknown 타입이 도입되기 이전에는 {}가 일반적으로 사용되었다. 최근에는 잘 사용하지 않는다.
정말로 null과 undefined가 불가능하다고 판단되는 경우에만 {}를 대신 사용해야 한다.
object 타입은 모든 비기본형(non-primitive) 타입으로 이루어진다. ex) 객체, 배열
아이템43몽키 패치보다는안전한타입을사용하기
요약
몽키패치란, 원래 소스코드를 변경하지 않고 실행 시 코드 기본 동작을 추가, 변경 또는 억제하는 기술을 의미한다. 자바스크립트에 있어서는 프로토타입에 특정 메소드 추가 한다거나 document 객체에 전역 변수를 삽입하는 등이 있다.
전역 변수나 DOM에 데이터를 저장하는 것보다 데이터를 분리하여 사용해야 한다.
어쩔수 없이 내장 타입에 데이터를 저장해야 하는 경우, 안전한 타입 접근법 중 하나인 보강이나 사용자 정의 인터페이스로 단언를 사용해야 한다
noImplicitAny로 암묵적인 any타입 사용을 금지 시켜도, 명식적 any 또는 서드파티 타입 선언(@types)을 통해 any 타입은 코드 내에 여전히 존재할 수 있다는 점을 주의하자.
작성한 프로그램 타입을 추적해 any 사용을 줄여나가자. npx type-coverage 를 사용해 프로젝트 심벌중 any 가 아닌 타입의 퍼센트를 확인할 수 있다. npx type-coverage --detail 를 사용해 any 타입이 있는 곳을 모두 출력할 수 있다.
$ npx type-coverage
// 9985 / 10117 98.69%
6장 타입 선언과 @types
아이템 45 devDependencies 에 typescript와 @types 추가하기
요약
typescript를 시스템 레벨(npm install -g typescript)로 설치하면 안 된다. typescript를 프로젝트의 devDependencies 에 포함시키고 팀원 모두가 동일한 버전을 사용하도록 해야 한다.
@types 의존성은 dependencies가 아니라 devDependencies에 포함시켜야 한다. 런타임에 @types 가 필요한 경우라면 별도의 작업이 필요할 수 있다.
타입 선언과 관련된 세가지 버전이 있다. 라이브러리 버전, @types 버전, typescript 버전이다. 이 세가지의 버전에 따라 타입스크립트 생태계에선 더욱 의존성이 관리가 복잡하게 되었다.
라이브러리를 업데이트하는 경우, 해당 @types 역시 업데이트를 하자.
라이브러리를 만들때 타입 선언을 관리하는 방법은 두가지가 있다.
방법1) 타입 선언을 DefinitelyTyped에 공개(= @types)해 라이브러리와 따로 두기
방법2) 타입 선언을 라이브러리에 포함시키기
공식적인 권장사항은 타입스크립트로 작성된 라이브러리인 경우만 타입 선언을 자체적으로 포함하는 것이다. 그 외의 경우(자바스크립트로 작성된 라이브러리)라면 타입을 DefinitelyTyped에 공개해 따로 관리하는게 좋다.
실제 라이브러리와 타입 정보의 버전이 별도로 관리되는 방식의 문제점
// 특정 라이브러리 - dependencies로 설치
$ npm install react
+ react@16.8.6
// 타입 정보 - devDependencies
$ npm install —save-dev @types/react
+ @types/react@16.8.19
-> 메이저버전과마이너버전(16.8)이일치하지만패치버전(.6과.19)은일치하지않다.
1. 라이브러리를 업데이트했지만 실수로 타입 선언은 업데이트하지 않는 경우 라이브러리 업데이트와 관련된 새로운 기능을 사용하려 할 때마다 타입 오류가 발생하게 됨
2. 라이브러리보다 타입 선언의 버전이 최신인 경우 타입 정보 없이 라이브러리를 사용해 오다가 타입 선언을 설치하려고 할 때 발생하게 됨 -> 타입 체커는 최신 API를 기준으로 코드를 검사하게 되지만 런타임에 실제로 쓰이는 것은 과거 버전
3. 프로젝트에서 사용하는 타입스크립트 버전보다 라이브러 리에서 필요로 하는 타입스크립트 버전이 최신인 경우 -> 프로젝트의 타입스크립트 버전을 올리거나 or 라이브러리 타입 선언의 버전을 원래대로 내리거나 or declare module 선언으로 라이브러리의 타입 정보를 없애 버리기
4. @types 의존성이 중복될 수 있음
아이템 47공개API에등장하는모든타입을익스포트하기
요약
공개 메서드에 등장한 어떤 형태의 타입이든 익스포트 하자. 어차피 라이브러리 사용자가 추출할 수 있으므로 익스포트 하기 쉽게 만드는 것이 좋다. (어차피 숨기는게 거의 불가능하다.)
타입스크립트는 구조적 타이핑을 사용하기 때문에, 값을 세밀하게 구분하지 못하는 경우가 있다.
값을 구분하기 위해 공식 명칭이 필요하다면 상표를 붙이는 것을 고려해야 한다.
상표 기법은 타입 시스템에서 동작하지만 런타임에서 상표를 검사하는 것과 동일한 효과를 얻을 수 있다.
타입 시스템이기 때문에 런타임 오버헤드를 없앨 수 있고 추가 속성을 붙일 수 없는 string이나 number 같은 내장 타입도 상표화 할 수 있다.
구조적 타이핑 : 실제 구조와 정의에 의해 결정되는 타입 시스템
예시 1. 벡터의 길이를 계산하는 함수
interface Vector2D {
x: number;
y: number;
}
function calculateNorm(p: Vector2D) {
return Math.sqrt(p.x * p.x + p.y * p.y);
}
calculateNorm({x: 3, y: 4}); // OK, result is 5
const vec3D = {x: 3, y: 4, z: 1};
calculateNorm(vec3D); // OK! result is also 5
Good
calculateNorm 함수가 3차원 벡터를 허용하지 않게 하려면 공식 명칭(nominal-typing)을 사용하면 된다.
공식 명칭을 사용하는 것은, 타입이 아니라 값의 관점에서 Vector2D라고 말하는 것
interface Vector2D {
_brand: '2d';
x: number;
y: number;
}
function vec2D(x: number, y: number): Vector2D {
return {x, y, _brand: '2d'};
}
function calculateNorm(p: Vector2D) {
return Math.sqrt(p.x * p.x + p.y * p.y); // Same as before
}
calculateNorm(vec2D(3, 4)); // OK, returns 5
const vec3D = {x: 3, y: 4, z: 1};
calculateNorm(vec3D);
// ~~~~~ Property '_brand' is missing in type...
그러나vec3D값에_brand: '2d'라고추가하는것같은악의적인사용을막을수는없다.
다만단순한실수를방지하기에는충분하다.
예시 2. 절대 경로를 사용해 파일 시스템에 접근하는 함수
Good
string 타입이면서 _brand 속성을 가지는 객체를 만들 수는 없다.
타입 AbsolutePath는 온전히 타입 시스템의 영역
만약 path 값이 절대 경로와 상대 경로 둘 다 될 수 있다면, 타입을 정제해 주는 타입 가드를 사용해서 오류를 방지할 수 있다.
type AbsolutePath = string & {_brand: 'abs'};
function listAbsolutePath(path: AbsolutePath) {
// ...
}
function isAbsolutePath(path: string): path is AbsolutePath {
return path.startsWith('/');
}
function f(path: string) {
if (isAbsolutePath(path)) {
listAbsolutePath(path);
}
listAbsolutePath(path);
// ~~~~ Argument of type 'string' is not assignable
// to parameter of type 'AbsolutePath'
}
예시 3. number 타입에 상표 붙이기
type Meters = number & {_brand: 'meters'};
type Seconds = number & {_brand: 'seconds'};
const meters = (m: number) => m as Meters;
const seconds = (s: number) => s as Seconds;
const oneKm = meters(1000); // 타입이 Meters
const oneMin = seconds (60); // 타입이 Seconds
하지만, number 타입에 상표를 붙여도 산술 연산 후에는 상표가 없어지기 때문에 실제로 사용하기에는 무리가 있다.
그러나 숫자의 단위를 문서화하는 괜찮은 방법일 수 있다.
const tenKm = oneKm * 10; // 타입이 number
const v = oneKm / oneMin; // 타입이 number
5장 any 다루기
아이템 38 any 타입은 가능한 한 좁은 범위에서만 사용하기
요약
의도치 않은 타입 안전성의 손실을 피하기 위해서 any의 사용 범위를 최소한으로 좁혀야 합니다.
함수의 반환 타입이 any인 경우 타입 안정성이 나빠집니다. 따라서 any 타입을 반환하면 절대 안 됩니다.
강제로 타입 오류를 제거하려면 any 대신 @ts-ignore 사용하는 것이 좋습니다.
예시 1. 함수 내에서 사용된 any
function f1() {
const x: any = expressionReturningFoo(); // 이렇게 하지 맙시다.
processBar(x);
}
function f2() {
const x = expressionReturningFoo();
processBar(x as any); // 이게 낫습니다.
}
f1 함수: x를 any 타입으로 지정 f2 함수: x가 사용되는 곳에 as any 단언문 사용
f2 함수가 권장되는 이유:
any 타입이 processBar 함수의 매개변수에서만 사용이 되기 때문에, 다른 코드에는 영향이 미치지 않음 !
반면에, f1 함수에서는 마지막까지 x가 any 타입이 유지된다.
f1 함수가 x를 반환한다면?
function f1() {
const x: any = expressionReturningFoo();
processBar(x);
return x;
function g() {
const foo = f1(); // 타입이 any
foo.fooMethod(); // 이 함수 호출은 체크되지 않습니다!
}
=> 함수 호출이 체크되지 않기 때문에 이렇게 사용하면 안됨
이렇게 any 타입인 x를 반환하는 함수를 사용하면 foo 타입까지 영향을 미치기 때문에, 프로젝트 전반에 전염병처럼 퍼지게 된다.
f2 함수 처럼 사용한다면 any 타입이 함수 바깥으로 영향을 미치지 않는다.
function f1() {
const x = expressionReturningFoo();
// @ts-ignore
processBar(x);
return x;
}
@ts-ignore 를 사용하여 오류를 무시할 수 있지만, 근본적인 원인을 해결한 것은 아니기 때문에 다른 곳에 더 큰 문제가 발생할 수 있음
const config: Config = {
a: 1,
b: 2,
c: {
key: value
}
} as any; // 이렇게 하지 맙시다!
하지만, 객체 전체를 any로 단언하면 다른 속성들 (a, b) 역시 타입 체크가 되지 않는다 ! 그러므로 아래처럼 최소한의 범위에만 any를 사용하는 것이 좋다.
const config: Config = {
a: 1,
b: 2, // 이 속성은 여전히 체크됩니다.
c: {
key: value as any
}
};
아이템 39 any를 구체적으로 변형해서 사용하기
요약
any를 사용할 때는 정말로 모든 값이 허용되어야만 하는지 면밀히 검토해야 한다.
any보다 더 정확하게 모델링 할 수 있도록 any[] 또는 {[id: string]: any} 또는 () => any처럼 구체적인 형태를 사용해야한다.
1. any를 사용할 때는 정말로 모든 값이 허용되어야만 하는지 면밀히 검토해야 한다.
any 타입은 모든 숫자, 문자열, 배열, 객체, 정규식, 함수, 클래스, DOM 엘레먼트, null, undefined 까지 포함한다.
일반적인 상황에서 any 보다 더 구체적으로 표현할 수 있는 타입이 존재할 가능성이 높다.
const numArgsBad = (...args: any) => args.length; //❌ return 타입이 any
const numArgsGood = (...args: any[]) => args.length; //✅ return 타입이 number
/**
후자가 더 좋은 이유
1. args.length 타입이 체크 됨
2. 함수 반환 타입이 number 로 추론 됨
3. 함수 호출 시, 매개변수가 배열인지 체크 됨
*/
2. any보다 더 정확하게 모델링 할 수 있도록 any[] 또는 {[id: string]: any} 또는 () => any처럼 구체적인 형태를 사용해야한다. (그냥 any 보다는 조금이라도 더 구체화시키려 노력하자.)
아이템 40. 함수 안으로 타입 단언문 감추기
요약
타입 단언문은 일반적으로 타입을 위험하게 만들지만 상황에 따라 필요하기도 하고 현실적인 해결책이 되기도 한다. 불가피하게 사용해야 한다면, 정확한 정의를 가지는 함수 안으로 숨기도록 한다.
가능한 안전한 타입으로 구현하는 것이 이상적이나, 불필요한 예외 상황까지 고려해 가며 타입 정보를 힘들게 구성할 필요는 없다.
함수 내부에서는타입 단언을 사용하고, 함수 외부로 드러나는 타입 정의를 명시하는 정도가 적절할 수 있다.
//예제 - 함수 캐싱하는 함수: 함수가 자신의 마지막 호출을 캐시(기억)하도록 만들어주는 함수
declare function shallowEqual(a: any, b: any): boolean;
function cacheLast<T extends Function>(fn: T): T {
let lastArgs: any[] | null = null;
let lastResult: any;
return function(...args: any[]) {
if (!lastArgs || !shallowEqual(lastArgs, args)) {
lastResult = fn(...args);
lastArgs = args;
}
return lastResult;
} as unknown as T;
}
//원본 함수 타입 T와 리턴하는 함수가 어떤 관련이 있는지 모르기 때문에 에러 발생!
//그려나 우리는 두 함수가 '같은 매개변수를 주면 같은 값을 반환하는' 함수여서
//동일하게 취급해도 문제 없다는 것을 알기때문에 단언문 사용해도 괜찮다.
속절없이 지나가는 시간들을 붙잡고 싶어 .. 쓰기 시작한 나의 첫 회고 항상 회고라는 것을 해보고 싶었지만, 바쁘다는 핑계로 미뤄왔었다. 하지만 좋은 기운들을 마주하고 잊지 않기 위해서, 누군가에게 전달받은 동기부여들을 잊지 않기 위해 기록해본다 🙌
이번 2024년은 정말 많은 것들이 변했다. 대운이 들어오기 전 오래 유지되었던 인간관계가 변하고, 새로운 사람들을 많이 만난다던데, 지금이 그 시기인듯하다. 가장 많이 변했다면 변한 2024년, 여러 사건들을 마주하며 심적으로 많이 힘들었지만, 혼자만의 시간을 제일 많이 보내면서 단단해진 것 같다 😇
1분기 (1~3월) : 1. 호주 여행 운이 좋게 친구가 퇴사하고, 나는 방학을 맞아 길다면 긴 2주간의 호주 여행을 다녀왔다. 호주가서 호주인이 다 된 고등학교 친구를 만나고, 또 처음보는 외국인들과 같이 놀면서 정말 재밌었다. 휴식하고 싶다는 마음 가짐으로 찾아간 호주 여행에서 세상은 넓고, 무엇이든 할 수 있겠다라는 마음으로 돌아왔다. 호주 워홀을 30대 이전에 꼭 가겠다는 마음으로 .. 돌아왔는데, 막상 한국이 더 좋긴 하다. 돈만 있으면 살기 좋은 곳 나라 = 한국
여행 다녀온 뒤, 유튜브에 여행 브이로그 만들어서 올렸다. 물론 영상 1개만 편집하고 그 이후에는 흥미가 떨어져서 못올렸다는 소문이 .. 다시 오세아니아를 간다면 기필코 호주 브리즈번과 퍼스, 뉴질랜드를 다시 가리라 ..
2. 숙대 졸업 졸업할 수 있을까? 외치던 내가 드디어 졸업을 했다. 많은 친구들과 가족들이 축하해준 덕분에 외롭지 않게 졸업할 수 있었다 ㅎㅎ 입학하고 스터디, 카이스트 몰입캠프, 큐시즘, 시스템 종합 설계 수업을 통해 많은 친구들을 만나고, 또 같이 개발하면서 정말 많은 것들을 배우게 되었는데 ,, 어쩌다 보니 개발인생이 되었다 ㅎㅎ 신기한 모먼트 전공 수업보다는 교양 수업들이 더 기억에 남고 재미있었다. 그 중 졸업하기 전에 마지막으로 들었던 비판적 사고와 토론 수업이 가장 기억에 남는다. 학우들과 하나의 논제를 가지고 찬성, 반대 근거를 가져와 토론을 하게 되는데, 각자의 근거를 준비해서 토론하는 이 과정이 너무 즐거웠다. 매도 먼저 맞는 것이 낫다고 ,, 내가 갑, 을, 병 중 갑이 되어서 입론을 펼치면서 토론을 시작했는데, 발표라고는 치를 떠는 내가 많은 학우들이 보고 있는 앞에서 토론을 진행하면서, 떨지 않고 발언하는 게 꽤 멋졌다. 많이 성장했군 ,, 덕분에 A 학점을 취득했고 매우 뿌듯했던 경험이었다. 팀원을 잘만나서 더더 재미있었다 ㅎㅎ
2. 구직 준비하면서 토익, 토익스피킹 자격증 따기 삼성 넣기 위해 처음으로 토스를 준비해봤는데,, 제니쌤과 함께 3일을 보내고 과감없이 시험을 쳐버렸다. 물론 좋은 결과는 아니지만, 턱걸이로 지원해볼 수 있었다 하 하 .. 근데 삼성이 인재를 못알아봤네 (?)
3. 운동 시작 처음으로 PT를 끊고 운동을 시작하게 되었다. 주연이랑 2인 PT하면서 더 좋은 시너지를 낼 수 있었다. 자기 관리 끝판왕 주연이를 보면서 식습관도 바꿀 수 있었고, 덕분에 더 재밌게 운동할 수 있었다 ㅎㅎ 가장 잘한 일 중 하나가 운동이라는 생각이 드는데, 5개월동안 체지방률 -4%, 근육 +1kg 늘렸다. 어쩌다보니 웨이트가 취미가 되고 있는데, 여전히 유산소는 하기 싫다 ㅎㅎㅎ
4. 프리랜서로 근무 운이 좋게 학교 공고글에 올라온 프론트엔드 모집 공고글을 보고 호다닥 지원했는데, 서류만 보고 바로 일하게 되었다. 처음으로 Next.js로 웹사이트 개발도 해보고, 팀에서 팀장(?)처럼 팀원을 관리하며 주도적으로 개발해보았다. 덕분에 취준 생활 ,, 풍요롭게 할 수 있었다..
2분기 (4~6월) : 1. 네이버 블로그 시작 가장 친한 친구와 네이버 블로그를 시작했다. 우리가 가장 익숙하고도 편안한 장소를 시작으로 후기를 남기고, 이웃들과 소통하면서 점점 늘어가는 이웃들을 보면서 뿌듯했다. 또 체험단도 열심히 다니면서 식비도 아끼고, 좋은 경험들을 할 수 있었다. 이후에 면접에서 최근에 한 일 중에 성과를 낸 경험이 있냐고 물어봤을 때 생각난게 네이버 블로그 ㅋㅋㅋㅋㅋ 태생이 N잡러일지도 모르겠다.. 블로거도 쉽지 않음 ,, ㅎㅎ
2. 요리 실력 운동을 하면서 자연스럽게 외식을 줄이고 몸에 좋은 음식을 먹기 위해 매일 같이 요리했다. 단호박, 오리고기, 닭가슴살 등의 식단을 통해서 나의 입맛이 변화시키고, 또 초코처돌이인 나는 코코아파우더도 구매해서 베이킹도 하기 시작. 물론 요즘은 식단을 열심히 안해서 베이킹은 안하지만,, 조만간 바프를 찍을 수도 있기 때문에 다시 시작 예정이다 ✨ 밤호박 철이던 시절이 그립군 ,,
내가 만든 에그타르트 / 초코케이크 / 즐겨먹던 식단
3. 태국 치앙마이 여행 엄마랑 외할머니랑 처음으로 여행을 갔다. 항상 자유여행만 가다가 어른들과 패키지 여행을 가게 됐는데, 버스에 앉아만 있으면 되니 더할나위없이 편했다. 외할머니랑 항상 명절에만 만나다가 이렇게 여행가니까 더욱 친해질 수 있었다 ㅎㅎ 할머니는 알고보니 .. 굉장히 까다로운 사람이었다.. 할머니와 처음이자 마지막일지도 모르는 여행이여서 더더욱 재밌었다. 행복해하시는 모습들을 보니 나 역시 행복했다. 송크란 축제 때 방문했으면 더 재밌었을 것 같은데, 그래도 투어리스트가 태국 역사와 카렌족 같은 원주민에 대해 얘기해주셔서 재밌었다 ㅎㅎ
4. 홍콩 여행 아마도 이때가 리즈 시절이 아니였을까 생각한다. 가장 말랐고.. 가장 예뻤나 (?) 아무튼 찍히는 모든 사진들이 마음에 쏙 들었다. 홍콩에서 정말 여러 일들이 있었는데,
- 처음으로 홍콩 공항에서 노숙해본 경험.. 애매한 시간에 도착해서 숙소 값 아까워 해외 공항에서 노숙해본 사람 있나요 ? 인천 공항처럼 인프라가 좋으면 모르겠으나, 의자 3개에서 웅크리고 자야했던 우리 ,, 정말 대단하다는 생각이 든다. 이런 경험도 젊을 때나 해보지 언제 해보겠어 (?)
- 길에서 만난 한국인과의 동행 마카오에서 친구랑 같이 걸어가던 중 혼자 오신 어머님이 우리보고 한국인이냐며 말을 거셨다. 지도 앱이 없으셔서 이정표만 보고 걷는다면서 동행하는 것이 어떠냐고 하셨다. 우리는 그렇게 동행하게 되고, 알고보니 한국에서 교수님이셨다. 덕분에 폴로 공장도 방문하게 되고, 마카오에서 맛있는 것도 많이 사주셨다.. 이 때 많이 사주신 덕분에 우리는 가까스로 홍콩으로 돌아가는 크루즈를 탈 수 있게 되었는데,, 정말 천운이었다 🥹 교수님께서 많은 조언을 해주셨는데,,, 가장 기억에 남는 말은 젊을 때 많이 여행다니라면서 나이 들면 돈은 많아도 감흥이 없다고 하셨다.
홍콩의 날씨는 무진장 더웠는데, 습함이 Max였다. 머리카락이 이마에 붙어있는 수준 ㅎㅎㅎ 현지에서 먹던 에그타르트와 밀크티, 납짝 복숭아가 너무너무 그립다 !
5. 네이버 부스트캠프 지원 웹 풀스택 개발자로 지원해서 코딩테스트도 보고, 입과자로 선정돼서 열심히 참여했다. (물론 1주차만..) 매일매일 요구사항을 분석하고 코드를 짜면서 금요일에는 4명의 팀원들과 하나의 문제를 풀었다. 그룹 미션을 진행하면서 다양한 사람들을 만날 수 있었고, 고등학교 동창도 만날 수 있었다.. 당황 이때 너무 바빠서 1주차만 진행하고 2주차는 함께하지 못했다.
3분기 (7~9월) : 회사에서 나의 가치를 인정받은 3달. 회사에 입사 이후 어떤 것을 얻었나?
1. 인재밀도 높은 사람들 만나기 해외 출신, 국내 탑 대학교 출신들과 만나면서 세상에는 정말 멋진 사람들이 많고, 더 넓은 사고를 통해 세상을 바라봐야한다는 것을 깨달았다. 또 나와 다르게 겸손한 사람들, 타인의 감정을 공감하고 이해하는 사람들을 보면서 정말 대단하고 멋지다는 생각이 들었다. 통근을 3시간 하면서 자연스레 예민해지고, 심적으로 여유가 없어지는 것을 깨닫고 있는 와중에,, 항상 밝은 얼굴로 인사해주는 사람들과 본인의 커리어와 방향성에 대해 항상 고민하고 성장하려는 사람들이 너무 멋지다. 그런 사람들을 만날 수 있어서 너무 즐거웠고, 또 나이가 비슷한 사람들과 함께 할 수 있어서 너무 행복했다.
2. 코드에 대한 두려움이 사라지다. 처음 사회생활을 시작하고 개발을 할 때에는 내가 짠 코드에 대해 100% 확신할 수 없었다. 얼렁뚱땅 개발해도 잘 돌아가니까 .. 해결되지 않는 문제들이 생겨나면 '내가 이 문제를 해결할 수 있을까?' 라는 생각이 온 몸을 지배했고, 그 압박감이 자연스레 디버깅하는 데 두려움을 안겨주었다. 하지만, 그동안의 기간동안 여러 프로젝트를 진행해보면서 개발자는 개발"만"하는 것이 아닌, 문제를 해결하는 사람이라는 것을 깨달았다. 어떤 문제가 발생하면 WHY와 HOW를 생각하며 디버깅했고, 두려워하지 않으니 자연스럽게 문제가 해결되었다. 이런 생각들이 개발적인 성장으로 이어졌고, 나에 대한 자신감으로 돌아왔다. 안되는 것도 되게 만들자 그게 개발자가 할 일
3. 앱 서비스 출시 오랜만에 서비스를 출시했다. 기존에 하던 테스트앱 배포, 개발, QA, 출시까지 완벽한 플로우로 이뤄졌다. 우리 앱은 외주로부터 이어졌지만, 내가 입사한 이후 "내 정보" 기능까지 개발하여 배포할 수 있었다. 그 중 패키지명 이슈가 있었는데, 아무런 패키지명으로 배포했다가 호되게 당했다. 패키지명은 서버 도메인을 따라야하고, 출시 이후에는 바꿀 수 없다는 점이 기억에 남는다. 또한, 처음으로 안드로이드 난독화해서 앱 출시도 해보고, 커머스 도메인 지식을 늘릴 수 있는 엄청난 기회였다. 현재는 다른 기능도 개발 진행중인데, 추후에는 비즈니스 성과를 꼭 증명할 수 있길 바랄 뿐이다.
4. 독서모임 시작 평소에 책이라고는 자기계발 쪽만 읽던 내가 고전을 읽게 되었다. 벌써 4권 째 ..!! 달과 6펜스에서 풍족한 현실을 버리고 과감히 본인의 이상을 추구하는 .. 스트릭랜드가 기억에 남는다. 난 절대 못해 며칠 전 홍기한테 "너 달과 6펜스에 나오는 스트릭랜드 같아" 이랬더니 걔는 본인보다 더하다면서 "그 사람 가정도 버리지 않았나? 나는 그렇겐 못해" 라고 했다 ㅋㅋㅋ
5. 해외구매대행 시작 인생 처음으로 사업자등록, 통신판매업 신고를 하면서 많은 어려움이 있었지만,, N잡의 재미를 보고 있다. 하지만 사업은 어려운법.. 소비자의 마음을 얻기란 쉽지 않다 ㅎㅎ 25살에 나의 커리어 목표를 잡을 수 있었는데, 목표를 향해 달려가는 나 제법 멋지다. 그곳에는 혼자가 아닌 제일 친한 친구와 함께 동행할 수 있음에 너무 감사할 따름 🙏
6. 인간관계의 변화 어렸을 때 친했던 친구들을 오랜만에 만나면 안맞는다는 생각이 들 때가 많다. 살아오면서 바뀐 가치관과 성격들이 고착화돼서 서로를 이해하지 못하게 만든다. 떠나갈 사람은 자연스럽게 떠나고, 나를 지켜줄 인연은 계속 유지된다. 인생은 내 마음대로 흘러가지 않을 뿐더러 스스로 통제하려해도 마음대로 되지 않는 것이다. 그러니 관계는 흘러가는 대로 두는 것이 가장 베스트인 듯 하다 😁
8. 스스로의 변화 동네 이상으로 멀리나가는 것을 싫어하던 내가 통근 시간이 거진 도합 3시간으로 다져진 습관으로 .. 이제 1시간은 무리 없다 ! 오히려 익숙한 공간에서 벗어나 새로운 공간에서 얻어지는 인사이트들이 삶을 더 풍요롭게 만든다. 역시 나는 뽀로로인가보다 .. 노는 게 제일 좋아
마무리 입사 이후 현실 생활에 집중하느라 정신없이 시간이 흘러버렸다. 몸이 2개는 아니지만, 하나에만 몰두하지말고 On/Off를 잘해서 여러 일들에 시간을 할애했으면 좋겠다. 이렇게 회고를 해보니 정말 열심히 살았구나 싶다. 올해 여행을 3번이나 갔다니 정말 만족스럽군 ㅎㅎㅎ 4분기에도 회고를 해야지 .. ! 그리고 linkedin 하는 person 있으면 알려주세요.. 팔로우하게 .. >.<
any 타입에는 타입 안정성이 없다. age는 number 타입으로 선언되었지만, as any를 사용하면 string 타입을 할당할 수 있게 된다. 따라서 아래처럼 선언될 가능성이 있다. ex. age += 1 // 런타임에 정상, age는 “121”
any 타입에는 언어 서비스가 적용되지 않는다. => ts 모토:확장 가능한 자바스크립트
타입이 있다면 타입스크립트 언어 서비스는 자동완성 기능과 적절한 도움말을 제공한다.
그러나 any 타입은 제공하지 않는다.
이름 변경 서비스도 제공하지 않는다.
interface Person {
first: string;
last: string;
}
const formatName = (p: Person) => `${p.first} ${p.last}`
const formatNameAny = (p: any) => `${p.first} ${p.last}`
--- 여기서 Rename Symbol을 클릭 해 이름 변경 ---
프로젝트 내의 심벌 이름이 모두 변경됨