타입스크립트 그룹스터디 - ChoDragon9/posts GitHub Wiki

https://www.typescriptlang.org/play

목차

  • 02.19 첫번째
  • 03.05 두번째
  • 03.12 세번째

02.19 첫번째

타입스크립트란

  • 정적 타입 검사 도구
  • 자바스크립트 슈퍼셋
    • 예) C++은 C의 슈퍼셋
    • 기존의 언어를 꾸며줌
  • 확장의 목적은 정적 타입 검사를 하기 위해
  • MS에서는 타입스크립트를 "새로운 언어가 아니다"라고 말함
    • "ECMAScript 문법을 따를 뿐 미래에 JS 문법이 될 것이다."라고 함.
  • Lint를 잘쓰려면?
    • Airbnb, ESLint 관련해서 룰을 잘 선언해야 함
  • 정적 타입을 잘쓰려면?
    • 타입 검사를 잘할 수 있게 타입을 잘 선언해야 함.
    • 자바스크립트가 어떻게 동작하는지 타입을 선언하는 것.

환경구성

  • tsconfig
    • 폴더마다 tsconfig을 만들수 있음
    • extends 옵션으로 확장해서 사용할 수 있음
    • files 옵션은 순서 결합도가 있음
      • tsconfig 파일만으로 자바스크립트를 export 할 수 있다.
  • input / output
    • input: tsconfig의 reference, files
    • output: tsconfig의 outFile 설정

타입스크립트 아키텍쳐

  • 주요 설계 목적
    • 정적 구문 식별
    • 상위 집합 언어
    • 구조화 메커니즘 제공
    • 제로 런타임 오버헤드
      • 설계 시간(디자인-타임)과 실행 시간(컴파일-타임)으로 구분
      • 디자인-타임: 작성한 코드를 의미
      • 컴파일-타임: 타입스크립트를 자바스크립트로 변환
    • ECMAScript 호환
    • 크로스 플랫폼
  • 타입스크립트 아키텍쳐
    • tsserver(server.ts)
    • Language Service(service.ts)
      • 디자인-타임
  • 타입스크립트 동작 과정
    • 타입 리졸버/체커
      • 진단(Diagnostic)
      • 타입 에러 발생 시, 문제있다고 보고해줌
    • TS 파일 컴파일 완료 시
      • JS 파일 내보냄
      • d.ts: 제거되는 타입을 선언함

Namespace

Namespace의 예제와 컴파일 결과

// 1.js
namespace ts {
    function test() {
        return 1
    }
    export function myFunc() {
        return test()
    }
}

// 2.js
namespace ts {
    export function myFunc2() {
        return myFunc()
    }
}
"use strict";
// 1.js
var ts;
(function (ts) {
    function test() {
        return 1;
    }
    function myFunc() {
        return test();
    }
    ts.myFunc = myFunc;
})(ts || (ts = {}));
// 2.js
(function (ts) {
    function myFunc2() {
        return ts.myFunc();
    }
    ts.myFunc2 = myFunc2;
})(ts || (ts = {}));

Interface도 병합하려고 한다.

// v1.js
interface MyI {
    age: number
    name: string
}

// v2.js
interface MyI {
    sex: string
}

Namespace에 Dot을 사용할 수 있다.

namespace ts {
    export function myFunction() {
    }
}

namespace ts.server {
    export function myFunction() {
    }
}

Enum

  • Block scoped / reference
  • 상수 효과를 볼 수 있다.
enum MyEnum {
    MyEnum0 = 0,
    MyEnum1 = 1,
    MyEnum2 = 2,
}

const myEnum0 = MyEnum[0]

console.log(myEnum0) // 0

enum MyEnum2 {
    MyEnum0 = '0',
    MyEnum1 = '1',
    MyEnum2 = '2',
}

console.log(Object.keys(MyEnum2)) // MyEnum0, MyEnum1, MyEnum2

const enum TokenFlags {
  None = 0
}

console.log(TokenFlags.None) // 0

숫자일 때는 내부에 접근할 수 있다.

enum MyEnum2 {
    MyEnum0 = 2,
    MyEnum1 = 2,
    MyEnum2 = MyEnum0 * MyEnum1,
}

console.log(MyEnum2.MyEnum2) // 4

03.05 두번째

추론

  • 특별한 힌트를 주지 않아도, 참조한 값을 알고 있는 것

Interface

  • 구조를 설명할 때 사용
  • 선언문

type

  • 별칭을 할 때 사용
  • 할당문
type MyFunc = (first: number, second: string) => string

const myFunc: MyFunc = (first, second) => {
  return second + first;
}

03.12 세번째

제네릭을 사용하는 이유?

  • 재사용성이 좋아짐. 생산성이 좋아짐
  • 힌트를 효율적으로 줄 수 있음
    • 자바스크립트와 같이 사용해서 추론 해줌

제네릭 선언과 호출, 인지가 있음.

interface Person<T> {
  name: string;
  age: number;
  etc: T;
}

type PersonExtra = Person<string>
type PersonExtraNumber = Person<number>

제네릭은 기본값을 줄 수 있음

interface Person<T, U = string> {
  name: string;
  age: number;
  etc: T;
  etc2: U;
}

type PersonExtra = Person<string>
type PersonExtraNumber = Person<number, number>

컨디셔널 타입

const FieldExtended = <
  T extends BaseFieldExtend,
  U extends
    T['type'] extends 'string'
      ? string
      : T['type'] extends 'date'
      ? Date
      : T['type'] extends 'float'
      ? number
      : never
  > (baseField: T & { value: U }) => baseField;

FieldExtended({
  type: 'date',
  name: 'a',
  value: new Date(),
});

infer

declare namespace Immutable {
  type DeepImmutable<T> =
    T extends (infer R)[] 
      ? DeepImmutableList<R>
      : T extends object
      ? DeepImmutableMap<T>
      : T;

  interface DeepImmutableMap<T> {
    get<K extends keyof T>(key: K): DeepImmutable<T[K]>
  }

  interface DeepImmutableList<T> {
    get(idx: number): DeepImmutable<T>
  }

  function fromJS<T> (source: T): DeepImmutable<T>
  function toJS<T> (obj: DeepImmutable<T>): T
}

const myState = [{a: {c: 1}}, 2];
const iList = Immutable.fromJS(myState);
const b = Immutable.toJS<typeof myState>(iList);

추론에서 유니온 제거

const myState = [{a: {c: 1}}, 2] as const;
const iList = Immutable.fromJS(myState);
const res = iList.get(1);
const b = Immutable.toJS<typeof myState>(iList);

오픈소스에서 기본 타입을 any로 했을 때 오버라이드를 한다.

declare module 'react-redux' {
  export function useStore<
    S = RootState,
    A extends Action = AnyAction
  > (): Store<S, A>
}

infer로 내부를 추론할 수 있다.

type UnwrapData<T> = T extends WrapperData<infer X> ? X : never;
⚠️ **GitHub.com Fallback** ⚠️