본문 바로가기

TypeScript

u[#. TypeScript] TypeScript 기초, 기본 개념 시작하기

반응형

 

 

 

 

 

 

TypeScript를 쓰는 이유

 

  • 큰 프로젝트일수록 JS의 자유도는 독이 된다
  • 에러 메시지 퀄리티가 높다

 

 

 

* React에서 TypeScript를 사용한다면 .ts 대신 .tsx를 사용해야 한다

.ts는 순수 TypeScript 파일에 사용하고 .tsx는 JSX를 포함하는 파일에 사용하기 때문이다

.ts 파일에서 React를 사용하면 에러가 발생한다 

 

 

 

 

 

 

 

 

@ JavaScript와 TypeScript 차이점

 

JavaScript TypeScript
- 컴파일 필요(to JS)
동적(Dynamic) 언어 정적(Static) 언어
Runtime 에러 발생 Runtime 전에 에러 발생
Interfaces, Generics X Interfaces, Generics O

 

배포 전에 JavaScript로 컴파일되어야 한다 

 

 

 

 

 

 

 

 

 

 

 

① typscript 전역 설치 

 

$ npm install -g typescript

 

잘 설치됐다면 아래 명령어를 입력했을 때 설치한 버전이 뜰 것이다

 

$ tsc -v
// Version 4.5.2

 

 

 

 

 

 

② src/main.ts 파일 생성

 

function getPrice(price: number, discount: number) {
  return price - discount;
}

console.log(getPrice(1000, 0));
console.log(getPrice(1000, '20%'));

 

src 폴더에 있는 main.ts을 컴파일하면 main.js 파일이 생성된다

number 타입인 discount에 string이 들어갔기 때문에 에러가 발생하지만 main.js 파일을 생성한다

 

$ tsc src/main

 

 

--noEmitOnError 옵션을 true로 주면 에러가 있을 때 에러를 수정할 때까지 js 파일을 생성하지 않는다

 

$ tsc src/main --noEmitOnError true

 

 

 

 

 

③ tsconfig.json 파일 생성

 

main.ts 파일이 있는 경로에 tsconfig.json 파일을 생성해 보자

 

{
  "compilerOptions": {
      "noEmitOnError": true,
      "target": "es5",
      "watch": true
  }
}

 

tsconfig.json 파일이 있는 경로에서 아래 명령어를 실행하면

파일 옵션에 따라 자동으로 컴파일되는 것을 볼 수 있다

 

$ tsc

 

혹은 config 설정 없이 아래 명령어를 입력한다

-w는 watch로 ts 파일 변경을 감지해서 자동으로 컴파일한다

 

$ tsc -w

 

 

 

 

⑴ tsconfig.json init 파일 생성하기

 

$ tsc --init

 

아래와 같이 모든 옵션이 주석처리 되어서 포함된 파일이 생성된다

 

{
  "compilerOptions": {
    /* Visit https://aka.ms/tsconfig.json to read more about this file */

    /* Projects */
    // "incremental": true,                              /* Enable incremental compilation */
    // "composite": true,                                /* Enable constraints that allow a TypeScript project to be used with project references. */
    // "tsBuildInfoFile": "./",                          /* Specify the folder for .tsbuildinfo incremental compilation files. */
    // "disableSourceOfProjectReferenceRedirect": true,  /* Disable preferring source files instead of declaration files when referencing composite projects */
    // "disableSolutionSearching": true,                 /* Opt a project out of multi-project reference checking when editing. */
    // "disableReferencedProjectLoad": true,             /* Reduce the number of projects loaded automatically by TypeScript. */

    /* Language and Environment */
    "target": "es2016",                                  /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
    // "lib": [],                                        /* Specify a set of bundled library declaration files that describe the target runtime environment. */
    // "jsx": "preserve",                                /* Specify what JSX code is generated. */
    // "experimentalDecorators": true,                   /* Enable experimental support for TC39 stage 2 draft decorators. */
    // "emitDecoratorMetadata": true,                    /* Emit design-type metadata for decorated declarations in source files. */
    // "jsxFactory": "",                                 /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */
    // "jsxFragmentFactory": "",                         /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
    // "jsxImportSource": "",                            /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */
    // "reactNamespace": "",                             /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */
    // "noLib": true,                                    /* Disable including any library files, including the default lib.d.ts. */
    // "useDefineForClassFields": true,                  /* Emit ECMAScript-standard-compliant class fields. */

    /* Modules */
    "module": "commonjs",                                /* Specify what module code is generated. */
    // "rootDir": "./",                                  /* Specify the root folder within your source files. */
    // "moduleResolution": "node",                       /* Specify how TypeScript looks up a file from a given module specifier. */
    // "baseUrl": "./",                                  /* Specify the base directory to resolve non-relative module names. */
    // "paths": {},                                      /* Specify a set of entries that re-map imports to additional lookup locations. */
    // "rootDirs": [],                                   /* Allow multiple folders to be treated as one when resolving modules. */
    // "typeRoots": [],                                  /* Specify multiple folders that act like `./node_modules/@types`. */
    // "types": [],                                      /* Specify type package names to be included without being referenced in a source file. */
    // "allowUmdGlobalAccess": true,                     /* Allow accessing UMD globals from modules. */
    // "resolveJsonModule": true,                        /* Enable importing .json files */
    // "noResolve": true,                                /* Disallow `import`s, `require`s or `<reference>`s from expanding the number of files TypeScript should add to a project. */

    /* JavaScript Support */
    // "allowJs": true,                                  /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */
    // "checkJs": true,                                  /* Enable error reporting in type-checked JavaScript files. */
    // "maxNodeModuleJsDepth": 1,                        /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */

    /* Emit */
    // "declaration": true,                              /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
    // "declarationMap": true,                           /* Create sourcemaps for d.ts files. */
    // "emitDeclarationOnly": true,                      /* Only output d.ts files and not JavaScript files. */
    // "sourceMap": true,                                /* Create source map files for emitted JavaScript files. */
    // "outFile": "./",                                  /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */
    // "outDir": "./",                                   /* Specify an output folder for all emitted files. */
    // "removeComments": true,                           /* Disable emitting comments. */
    // "noEmit": true,                                   /* Disable emitting files from a compilation. */
    // "importHelpers": true,                            /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
    // "importsNotUsedAsValues": "remove",               /* Specify emit/checking behavior for imports that are only used for types */
    // "downlevelIteration": true,                       /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
    // "sourceRoot": "",                                 /* Specify the root path for debuggers to find the reference source code. */
    // "mapRoot": "",                                    /* Specify the location where debugger should locate map files instead of generated locations. */
    // "inlineSourceMap": true,                          /* Include sourcemap files inside the emitted JavaScript. */
    // "inlineSources": true,                            /* Include source code in the sourcemaps inside the emitted JavaScript. */
    // "emitBOM": true,                                  /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
    // "newLine": "crlf",                                /* Set the newline character for emitting files. */
    // "stripInternal": true,                            /* Disable emitting declarations that have `@internal` in their JSDoc comments. */
    // "noEmitHelpers": true,                            /* Disable generating custom helper functions like `__extends` in compiled output. */
    // "noEmitOnError": true,                            /* Disable emitting files if any type checking errors are reported. */
    // "preserveConstEnums": true,                       /* Disable erasing `const enum` declarations in generated code. */
    // "declarationDir": "./",                           /* Specify the output directory for generated declaration files. */
    // "preserveValueImports": true,                     /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */

    /* Interop Constraints */
    // "isolatedModules": true,                          /* Ensure that each file can be safely transpiled without relying on other imports. */
    // "allowSyntheticDefaultImports": true,             /* Allow 'import x from y' when a module doesn't have a default export. */
    "esModuleInterop": true,                             /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */
    // "preserveSymlinks": true,                         /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
    "forceConsistentCasingInFileNames": true,            /* Ensure that casing is correct in imports. */

    /* Type Checking */
    "strict": true,                                      /* Enable all strict type-checking options. */
    // "noImplicitAny": true,                            /* Enable error reporting for expressions and declarations with an implied `any` type.. */
    // "strictNullChecks": true,                         /* When type checking, take into account `null` and `undefined`. */
    // "strictFunctionTypes": true,                      /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
    // "strictBindCallApply": true,                      /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */
    // "strictPropertyInitialization": true,             /* Check for class properties that are declared but not set in the constructor. */
    // "noImplicitThis": true,                           /* Enable error reporting when `this` is given the type `any`. */
    // "useUnknownInCatchVariables": true,               /* Type catch clause variables as 'unknown' instead of 'any'. */
    // "alwaysStrict": true,                             /* Ensure 'use strict' is always emitted. */
    // "noUnusedLocals": true,                           /* Enable error reporting when a local variables aren't read. */
    // "noUnusedParameters": true,                       /* Raise an error when a function parameter isn't read */
    // "exactOptionalPropertyTypes": true,               /* Interpret optional property types as written, rather than adding 'undefined'. */
    // "noImplicitReturns": true,                        /* Enable error reporting for codepaths that do not explicitly return in a function. */
    // "noFallthroughCasesInSwitch": true,               /* Enable error reporting for fallthrough cases in switch statements. */
    // "noUncheckedIndexedAccess": true,                 /* Include 'undefined' in index signature results */
    // "noImplicitOverride": true,                       /* Ensure overriding members in derived classes are marked with an override modifier. */
    // "noPropertyAccessFromIndexSignature": true,       /* Enforces using indexed accessors for keys declared using an indexed type */
    // "allowUnusedLabels": true,                        /* Disable error reporting for unused labels. */
    // "allowUnreachableCode": true,                     /* Disable error reporting for unreachable code. */

    /* Completeness */
    // "skipDefaultLibCheck": true,                      /* Skip type checking .d.ts files that are included with TypeScript. */
    "skipLibCheck": true                                 /* Skip type checking all .d.ts files. */
  }
}

 

 

 

⑵ typescript 파일 실행하기

 

ts => js 파일로 컴파일 완료 후 main.js 파일이 생겼다면 이 파일을 실행하면 된다

 

$ node main.js

 

console.log()로 콘솔에 값을 출력하도록 해둔 코드들이 잘 출력되는 것을 볼 수 있다

 

 

 

 

 

 

④ Typescript Type

 

  • string: 텍스트 데이터
  • boolean: true/ false 값
  • number: 숫자 값
  • symbol: Symbol 생성자를 호출하여 생성된 고유 값
  • any: 코드를 작성할 때 알 수 없는 다양한 유형의 값을 보유할 수 있는 변수
  • unknown: any의 대응물이지만 unknown에서는 먼저 구체적인 유형으로 확고히 하거나 범위를 좁히지 않으면 작업이 허용되지 않는다
  • never: 연결할 수 없는 코드를 나타내는 경우
  • void: value의 부재

 

 

⑴ 기본 타입

 

 

ⓐ Symbol

 

const sym1 = Symbol("11");
const sym2 = Symbol("11");

console.log(sym1 == sym2);	// false

 

 

 

null, undefined

값이 할당되지 않음, 값을 반환하지 않는 함수

null: 의도적인 값의 부재

 

 

 

ⓑ never

 

  • 절대 발생할 수 없는 타입을 나타낸다
  • 함수 표현식이나 화살표 함수 표현식에서 항상 에러를 던지며 값을 절대 반환하지 않는 함수에 할당된다
  • 모든 타입에 할당 가능한 최하위 타입이다
  • 함수의 마지막에 도달할 수 없다

 

let foo: never = 123;

// Type 'number' is not assignable to type 'never'

let a: any = 1;
let b: never;
a = b;	// 가능
b = a;	// 에러

위에서처럼 never 타입으로 정한 변수에는 다른 타입이 할당되지 않는다

하지만 하위 타입이기 때문에 다른 타입에는 할당 가능하다

 

 

function foo2(x: string | number): boolean {
  if (typeof x === "string") {
    return true;
  } else if (typeof x === "number") {
    return false;
  }
  return failMsg("ERROR!");
}
function failMsg(message: string): never { throw new Error(message); }

let tmp: any = {name: "test"}
console.log(foo2(tmp));	// ERROR!

함수의 마지막에 도달할 수 없다는 말은 => 항상 에러를 출력하거나 리턴 값을 절대로 내보내지 않는다는 것이다

never => void로 바꾸면 에러가 발생한다

 

 

 

never vs void

차이점은 void는 null 혹은 undefined 값의 반환을 허용하지만 never는 허용하지 않는다는 것이다

 

function noReturn(msg: string): never {
  console.log(msg);
}

 

 

 

ⓒ void

void 타입은 변수 선언에서 사용할 수 없다 value 값을 반환하지 않는 함수를 선언할 때 사용한다
never 타입과 달리 void 타입은 실행을 완료하지만 값을 반환하지 않는다

 

function checkLog(logMessage: string): void {
    console.error(logMessage);
}

 

 

함수에서 return하는 값이 없으면 undefined을 반환한다 void 타입은 프로그래머가 함수에서 실수로 명시적 값을 반환하는 것을 방지하기 위해 사용할 수 있다

 

 

 

ⓓ unknown

TypeScript의 상위 타입(Top-Type)이다

any 타입과의 공통점은 unknown 타입에 어떤 타입의 값도 할당할 수 있다는 것이다 

차이점은 any 타입의 값은 어느 타입의 변수에도 할당될 수 있으나, unknown 타입의 값은 any와 unknown 타입을 제외한 타입의 변수에는 할당이 불가능하다는 것이다

사실 any를 사용하는 것은 JS를 사용하는 것과 비슷하기 때문에 지양하는 게 맞다

unknown은 프로퍼티에 접근할 수 없고 메서드를 호출할 수 없으며 인스턴스를 생성할 수 없다

 

const typeAny: any = 10; // any에 어떤 것도 집어넣을 수 있다
const typeUnknown: unknown = 10; // any처럼 unknown에도 어떤 것도 집어넣을 수 있다
 
let str1: string = typeAny; // any는 어떤 것에도 집어넣어진다 
let str2: string = typeUnknown; // Invalid! unknown은 any나 unknown을 제외한 다른 타입에 할당할 수 없다 
let str3: unknown = typeUnknown; // 같은 unknown 타입 또는 any 타입에는 할당 가능
 
// unknown 타입은 어떤 프로퍼티에도 접근이 불가능하다

let bar: boolean = (typeUnknown as boolean);		// 할당하기 위해선 이렇게 타입을 명시해 줘야 한다

 

 

const typeAny: any = 10;
const typeUnknown: unknown = 10; 

let str1: string = typeAny;
let str2: string = typeUnknown;	// Type 'unknown' is not assignable to type 'string' error

console.log(typeof(str1));	// number

 

위 경우에 str2의 타입을 분명히 string으로 지정했지만 str1의 타입을 찍어보면 number가 된다

이게 바로 any가 발생시킨 문제이다

이런 문제를 막기 위해 unknown은 any가 아닌 다른 타입을 지정했을 경우 할당이 되지 않는 것이다 

 

 

 

⑵ 유틸리티 타입 ⭐️

 

 

 

ⓐ Partial

지정된 형식의 모든 하위 집합을 나타내는 형식을 반환한다 

프로퍼티 중 일부를 사용하고자 할 때 쓴다

자율성이 높기 때문에 일부를 쓴다고 선언했지만 프로퍼티를 아무것도 쓰지 않아도 문제가 없다

 

Partial<Type>

 

 

interface Todo {
  title: string;
  description: string;
}
 
function updateTodo(todo: Todo, fieldsToUpdate: Partial<Todo>) {
  return { ...todo, ...fieldsToUpdate };
}
 
const todo1 = {
  title: "organize desk",
  description: "clear clutter",
};
 
const todo2 = updateTodo(todo1, {
  description: "throw out trash",
});

 

 

 

ⓑ Omit

Key와 일치하는 프로퍼티는 제거한다

 

Omit<Type, Keys>

 

 

interface Todo {
  title: string;
  description: string;
  completed: boolean;
  createdAt: number;
}
 
type TodoPreview = Omit<Todo, "description">;
 
const todo: TodoPreview = {
  title: "Clean room",
  completed: false,
  createdAt: 1615544252770,
};
 
todo;
 
const todo: TodoPreview
 
type TodoInfo = Omit<Todo, "completed" | "createdAt">;
 
const todoInfo: TodoInfo = {
  title: "Pick up kids",
  description: "Kindergarten closes at 5pm",
};
 
todoInfo;

 

 

 

ⓒ Pick

Key와 일치하는 프로퍼티를 선택한다

선택한 프로퍼티는 반드시 사용해야 한다

 

Pick<Type, Keys>

 

 

interface Todo {
  title: string;
  description: string;
  completed: boolean;
}
 
type TodoPreview = Pick<Todo, "title" | "completed">;
 
const todo: TodoPreview = {
  title: "Clean room",
  completed: false,
};
 
todo;

 

todo에서 completed 프로퍼티를  빼면 

 

const todo: TodoPreview = {
  title: "Clean room",
};

 

Property 'completed' is missing in type '{ title: string; }' but required in type 'TodoPreview'

에러 메시지가 뜨는 것을 볼 수 있다

 

 

 

ⓓ Required

Partial와 반대다 

Pick과 같으나, Required는 key 값 없이 Type만 입력하면 된다

입력한 타입을 모두 필수로 사용해야 한다

 

Required<Type>

 

 

interface Props {
  a?: number;
  b?: string;
}
 
const obj: Props = { a: 5 };
 
const obj2: Required<Props> = { a: 5 };
// Property 'b' is missing in type '{ a: number; }' but required in type 'Required<Props>'

const obj3: Required<Props> = { a: 5, b: '2' };

 

 

 

ⓔ Readonly

타입의 모든 속성이 읽기 전용으로 설정된 타입을 생성한다 즉, 생성된 타입의 속성을 재할당할 수 없다

 

Readonly<Type>

 

 

 

interface Todo {
  title: string;
}
 
const todo: Readonly<Todo> = {
  title: "Delete inactive users",
};
 
todo.title = "Hello";
// Cannot assign to 'title' because it is a read-only property.

 

 

 

ⓕ Record

속성 키가 키이고 속성 값이 타입인 개체 형식을 구성한다 이 유틸리티를 사용하여 한 타입의 속성을 다른 타입에 매핑할 수 있다

 

Record<Keys, Type>

 

 

interface CatInfo {
  age: number;
  breed: string;
}	// value의 type
 
type CatName = "miffy" | "boris" | "mordred";	// key값 
 
const cats: Record<CatName, CatInfo> = {
  miffy: { age: 10, breed: "Persian" },
  boris: { age: 5, breed: "Maine Coon" },
  mordred: { age: 16, breed: "British Shorthair" },
};
 
cats.boris;	// { age: 5, breed: 'Maine Coon' }

 

 

 

ⓖ Exclude

Type에서 ExcludedUnion에 할당할 수 있는 모든 멤버를 제외하고 형식을 구성한다

Exclude<Type, ExcludedUnion>

 

 

type T0 = Exclude<"a" | "b" | "c", "a">;	// "b" | "c"
     
type T1 = Exclude<"a" | "b" | "c", "a" | "b">;	// "c"

T에서 U와 일치 일치하는 값을 제외한 나머지 값을 반환한다

 

 

 

ⓗ Extract

Union에 할당할 수 있는 모든 유니언 멤버 입력에서 추출하여 형식을 구성한다

 

Extract<Type, Union>

 

 

type T0 = Extract<"a" | "b" | "c", "a" | "f">;	// "a"

 

 

 

ⓘ NonNullable

Null을 제외하고 형식에서 정의되지 않은 형식을 구성한다

 

NonNullable<Type>

 

 

type T0 = NonNullable<string | number | undefined>;	// type T0 = string | number
type T1 = NonNullable<string[] | null | undefined>;	// type T1 = string[]

 

 

 

ⓙ Parameters

함수 타입 매개 변수에 사용된 형식에서 튜플 형식을 생성한다

 

Parameters<Type>

 

 

 

declare function f1(arg: { a: number; b: string }): void;
type T0 = Parameters<() => string>;
// type T0 = []

type T1 = Parameters<(s: string) => void>;
// type T1 = [s: string]

type T2 = Parameters<<T>(arg: T) => T>;
// type T2 = [arg: unknown]

type T3 = Parameters<typeof f1>;
/* type T3 = [arg: {
    a: number;
    b: string;
}] */

type T4 = Parameters<any>;
// type T4 = unknown[]

type T5 = Parameters<never>;
// type T5 = never

type T6 = Parameters<string>;
// Type 'string' does not satisfy the constraint '(...args: any) => any'.
// type T6 = never

type T7 = Parameters<Function>;
// Type 'Function' does not satisfy the constraint '(...args: any) => any'

 

 

 

 

 

 

⑤ Union Type

두 가지 이상의 타입으로 지정할 수 있다

 

let data: string | number;

 

 

// any

function padLeft(value: string, padding: any ): string {
    if (typeof padding === "number") {
        return Array(padding + 1).join(" ") + value;
    }
    if (typeof padding === "string") {
        return padding + value;
    }
    throw new Error(`Expected string or number, got '${padding}'.`);
}


console.log( padLeft("Hello world", 3));	//   Hello world(앞에 공백 4개 붙어 있음)
console.log( padLeft("Hello world", "John says "));	// John says Hello world 
console.log( padLeft("Hello world", true));	// Expected string or number, got 'true'. 
}

 

 

// union

function padLeft(value: string, padding: string | number ): string {
    if (typeof padding === "number") {
        return Array(padding + 1).join(" ") + value;
    }
    if (typeof padding === "string") {
        return padding + value;
    }
}

console.log( padLeft("Hello world", true));	// compile 에러

 

두 가지 이상의 타입을 보유할 수 있는 변수를 선언해야 하는 경우 any 대신 union을 사용해야 한다 혹은 let strData, let numData 처럼 타입별로 나눠서 사용하자

 

 

 

 

 

 

⑥ 사용자 정의 Type

 

 

⑴ Type alias

타입은 변수 담아서 쓸 수 있다 

 

type myType = string | number;

let myName : myType = 123;

 

type Cm = number;
type Kg = number;

type Patient = {
  name: string;
  height: Cm;
  weight: Kg;
}

let patient: Patient = {
  name: 'Joe Smith',
  height: 5
}
// Property 'weight' is missing in type '{ name: string; height: number; }' but required in type 'Patient'

 

 

 

⑵ option 프로퍼티

 

Patient에 들어있는 weight 프로퍼티가 빠져있기 때문에 에러가 발생한다

선택적인 프로퍼티면 ? key 값 뒤에 물음표 마크를 붙이면 된다 에러가 발생하지 않는다

 

type Patient = {
  name: string;
  height: Cm;
  weight?: Kg;
}

let patient: Patient = {
  name: 'Joe Smith',
  height: 5
}

 

 

 

⑶ 함수에 Type 지정

 

function myFunc(x: number): number {
  return x * 2
}

 

 

 

 

 

 

⑦ Enum(Enumeration) && Generic (열거형과 제네릭)

 

열거형을 사용하면 전반적으로 가독성이 높아진다

 

⑴ Numeric Enum(숫자 열거)

 

enum Week {           
  Monday = 2,
  Tuesday,
  Wednesday,
  Thursday,
  Friday,
  Saturday,
  Sunday
}

console.log(Week[2]);	// Monday

 

Monday 이후 값은 자동으로 +1씩 증가한다

Week[2]에서 2는 인덱스가 아니라 을 의미한다

 

 

 

⑵ String Enum(문자 열거)

숫자 열거와 달리 값을 알아도 ProductsTypes["Load"]로 멤버명을 가져올 수 없다 

 

enum ProductsTypes {
  Search = 'Search',
  Load = 'Load',
  LoadFailure = 'Failure',
  LoadSuccess = 'Success'
}

console.log(ProductsTypes.LoadFailure);	// Failure

 

 

 

⑶ Const Enum

Enum의 내용을 트랜스파일할 때 인라인으로 확장되고 JS가 생성되지 않는다고 한다 

아래 ⓐ, ⓑ의 경우 const 여부에 따라 인라인화(즉시 처리해서 JS에서 값만 보여준다)하여 JS로 컴파일한다

const enum을 사용하면 JS로 컴파일하는 구문을 단축할 수 있다

 

enum Direction {
  UP = 'Up',
  DOWN = 'Down',
  LSFT = 'Left',
  RIGHT = 'Right'
}

console.log(Direction.UP);	

// JS로 컴파일

"use strict";
var Direction;
(function (Direction) {
    Direction["UP"] = "Up";
    Direction["DOWN"] = "Down";
    Direction["LSFT"] = "Left";
    Direction["RIGHT"] = "Right";
})(Direction || (Direction = {}));
console.log(Direction.UP);

 

const enum Direction {
  UP = 'Up',
  DOWN = 'Down',
  LSFT = 'Left',
  RIGHT = 'Right'
}

console.log(Direction.UP);

// JS로 컴파일

"use strict";
console.log("Up" /* UP */);

 

 

 

 

 

 

⑧ Generic

 

포괄적인, 총칭(통칭)의

<> 기호를 이용해서 정의하며, 이름은 자유롭게 지정 가능하다 <T>와 같이 사용한다

재사용성을 위해 사용한다

선언 시점이 아니라 생성 시점에 타입을 명시하여 하나의 타입이 아닌 다양한 타입을 사용할 수 있게 해 준다

generic을 쓰지 않을 경우, 불필요한 타입 변환을 하기 때문에 프로그램의 성능에 악영향을 미칠 수 있다 하지만 generic을 사용하게 되면 따로 타입 변환을 할 필요가 없어서 프로그램의 성능이 향상되는 장점이 있다

 

// 선언 시
function concat<T>(str1: T, str2: T): T[] {
  return [strs, str2];
}
// 호출 시
const strArr = concat<string>('aaa', 'bbb');
const numArr = concat<number>(123, 456);

 

 

generic vs any

 

function identity<T>(arg: T): T {
    return arg;
}

identity(1);

 

generic은 모든 타입을 허용하되 어떤 타입의 데이터를 사용할지 호출 시에 개발자가 정하는 것이고, any는 어떤 타입이 들어와도 허용하는 것이다

<T>로 선언한 후에 인자를 넣을 때(호출될 때) function의 타입을 <string>이나 <number>로 명시할 수 있다 any와 달리 타입을 동적으로 결정한다

identity 함수에 T라는 타입 변수를 추가했다 T는 유저가 준 인수의 타입을 캡처하고 (number), 이 정보를 나중에 사용할 수 있게 한다

여기에서는 T를 반환 타입으로 다시 사용한다 인수와 반환 타입이 같은 타입을 사용하고 있는 것을 확인할 수 있다 이를 통해 타입 정보를 함수의 한쪽에서 다른 한쪽으로 운반할 수 있게끔 한다

identity 함수는 타입을 불문하고 동작한다

 

 

 

 

 

 

⑨ Decorator

 

데코레이터는 Javaannotation과 비슷한 느낌이 드는 함수로, 데코레이터가 붙은 클래스, 메소드(함수) 및 변수 등에 데코레이터에서 정의된 기능이 동작하는 것을 의미한다

메서드나 클래스 인스턴스가 만들어지는 런타임에 실행된다 즉, 매번 실행되지 않는다

클래스, 프로퍼티, 메서드 등에 이전에는 제공하지 않던 방법으로 새로운 기능을 추가할 수 있다

호출 순서는 프로퍼티 => 메서드 => 파라미터 => 클래스 순이다

 

  • 파라미터(parameter)
  • 프로퍼티(property)
  • 메서드(method)
  • 클래스(class)

 

⑴ tsconfig.json 설정

 

데코레이터를 사용하기 위해서는 설정을 해줘야 한다

 

 

{
  "compilerOptions": {
    "experimentalDecorators": true	// 추가
  }
}

 

 

 

⑵ Class Decorator

 

  • 클래스 선언 직전에 선언된다
  • 클래스 데코레이터는 클래스 생성자에 적용되며 클래스 정의를 관찰, 수정 또는 대체하는 데 사용할 수 있다
  • 클래스 데코레이터가 값을 반환하면 클래스 선언을 제공된 생성자 함수로 바꾼다

 

function hello(constructFn: Function) {
  console.log(constructFn);
}

function helloFactory(show: boolean) {
  if(show) {
    return hello;
  } else {
    return null;
  }
}

@helloFactory(true)
class Person {

}

 

 

 

⑶ Method Decorator

 

  • 함수 선언 직전에 선언된다
  • 클래스 데코레이터와 마찬가지로 함수 정의를 관찰하거나 수정할 때 사용한다
  • 메서드 데코레이터 내 expression은 런타임에 함수처럼 호출된다
  • ES5보다 낮은 JavaScript인 경우 무시한다

 

function editable(canBeEditable: boolean) {
  return function(target: any, propName: string, description: PropertyDescriptor) {
    console.log(target, propName, description);
    
  }
}

class Person {
  constructor() {
    console.log('new Pesron()');    
  }

  @editable(true)
  hello() {
    console.log('hello');
    
  }
}

/* Person {} 'hello' { value: [λ: hello],
writable: true,
enumerable: false,
configurable: true } */

 

 

 

⑷ Property Decorator

 

function writable(canBeWritable: boolean) {
  return function(target: any, propName: string): any {
    console.log(target);
    console.log(propName);
    
    return {
      writable: canBeWritable
    }
  }
}

class Person {
  @writable(true)
  name: string = 'dev';

  constructor() {
    console.log('new Person()');  
  }
}

const p = new Person();
console.log(p.name);

/*
Person {}
name
new Person()
dev
*/

 

 

 

⑸ Parameter Decorator

 

 

function printInfo(target: any, methodName: string, paramIndex: number) {
  console.log(target);
  console.log(methodName);
  console.log(paramIndex);
}

class Person {
  private _name: string;
  private _age: number;

  constructor(name: string, @printInfo age: number) {
    this._name = name;
    this._age = age;
  }

  hello(@printInfo msg: string) {
    console.log(msg);
    
  }
}

const p = new Person("dev", 20);

/*
Person { hello: [Function] }
hello	// 메서드 이름
0
[Function: Person]
undefined
1
*/

 

 

 

 

 

 

➉ OOP

 

⑴ Class

 

ⓐ 접근 제한자

 

Public, Private, Protected

 

접근 가능 여부 Public Protected Private
클래스 내부 O O O
자식 클래스 내부 O O X
클래스 인스턴스 O X X

 

class Person {
  public firstName = "first";
  private lastName = "last";
  protected age = 0;

  sayHello(): string {
    return `My name is ${this.firstName} ${this.lastName}`;
  }
}

class Employee extends Person {
  department = "dpt";
  subclassInnerFn = this.firstName;
  subclassInnerLn = this.lastName; // Property 'lastName' is private and only accessible within class 'Person'.
  subclassInnerAge = this.age;
}

const emp = new Employee();

console.log(emp.firstName);
console.log(emp.lastName);  // Property 'lastName' is private and only accessible within class 'Person'
console.log(emp.age); // Property 'age' is protected and only accessible within class 'Person' and its subclasses

 

 

 

ⓑ Static

 

static을 붙여서 정적 메서드를 정의한다 클래스의 인스턴스가 아닌 클래스 이름으로 호출한다

클래스의 인스턴스를 생성하지 않아도 호출 가능하다

 

class Gangsta {
  static totalBullets = 100;
 
  static shoot(){
    Gangsta.totalBullets--;
    console.log(`Bullets left: ${Gangsta.totalBullets}`);
  }
}
 
Gangsta.shoot();	// Bullets left: 99

 

 

 

ⓒ super()

부모(슈퍼) 클래스의 생성자는 자식(서브) 클래스의 생성자에서 자동 호출되지 않는다 따라서 서브클래스의 생성자에선 반드시 super 키워드를 사용해 슈퍼클래스의 생성자를 호출해 줘야 한다 이러한 방식으로 부모클래스의 필드에 값을 전달할 수도 있다

 

class Base {
  baseProp: number;
  constructor() {
    this.baseProp = 123;
  }
}
class Sub extends Base {
  constructor() {
    super(); // 반드시 이 호출을 직접 해 주어야 한.
    this.baseProp = 456;
  }
}
const s = new Sub();
console.log(s);	// Sub { baseProp: 456 }

 

 

 

ⓓ 추상화

추상 클래스를 정의할 때는 class 앞에 abstract라고 표기한다  또한 추상 메서드를 정의할 때도 abstract를 메서드 이름 앞에 붙인다

추상 메서드는 정의만 있을 뿐 body가 구현되어 있지 않다 추상 메서드의 내용은 상속을 받은 곳에서 반드시 구현해야 한다

추상 메서드는 추상 클래스 안에서 사용할 수 있다(Abstract methods can only appear within an abstract class)

 

abstract class Car {
  color: string;
  constructor(color: string) {
    this.color = color;
  }

  start() {
    console.log("start");    
  }

  abstract doSomething(): void;
}

class Benz extends Car {
  constructor(color: string) {
    super(color);
  }
  
  doSomething() {
    console.log("abstract method");    
  }
}

const dreamCar = new Benz("black");
console.log(dreamCar);	// Benz { color: 'black' }

 

 

 

ⓔ 메서드 오버로딩(Overloading)

같은 이름의 함수(메서드)를 여러개 정의하고, 매개변수의 유형과 개수를 다르게 하여 다양한 유형의 호출에 응답할 수 있게 하는 것이다

 

class ProductService {
 
  getProducts(): void;
  getProducts(id: number): void;
  getProducts(id?: number) {
      if (typeof id === 'number') {
        console.log(`Getting the product info for ${id}`);
      } else {
        console.log(`Getting all products`);
      }
  }
}

const prodService = new ProductService();

prodService.getProducts(123); // Getting the product info for 123
prodService.getProducts();  // Getting all products

 

 

 

⑵ Interface ⭐️

 

인터페이스는 ES6가 지원하지 않는 타입스크립트만의 특징이다 인터페이스는 타입이며 컴파일 후에 사라진다

추상 클래스는 선언과 구현이 모두 존재하지만 인터페이스는 선언만 존재하며, 멤버 변수와 멤버 메서드를 선언할 수 있지만 접근 제한자는 설정할 수 없다
클래스와 달리 interface는 TypeScript의 컨텍스트 내에서만 존재하는 가상 구조이다 TypeScript 컴파일러는 타입 체크 목적으로만 인터페이스를 사용한다 코드가 JavaScript 언어로 트랜스 파일되면 인터페이스가 제거된다

인터페이스는 클래스와 비슷한데, 클래스와 달리 정의만 할뿐 실제 구현되지 않는다 즉, 어떠한 객체를 생성 했을 때 가져야 할 속성 또는 메서드를 정의한다 (추상 클래스와 유사)

클래스에서 구현부가 빠졌다고 이해하면 편하다 어떠한 객체가 이러이러한 프로퍼티 혹은 메소드를 가진다고 선언하는 것이다 실질적인 구현은 이를 구현한다고 선언하는 클래스에 맡긴다

Type을 Object화한 그룹으로 이해했다

 

 

ⓐ 변수 Interface

 

type Score = 'A' | 'B' | 'C'

interface User {
  name: string;
  age: number;
  gender?: string;
  [grade: number]: Score;
}

let user: User = {
  name: 'dev',
  age: 20,
  1: 'A',
}

user.gender = "male";
console.log(user);	// { '1': 'A', name: 'dev', age: 20 }

 

 

ⓑ 함수 Interface

 

interface Add {
  (num1: number, num2: number): number;
}

const add: Add = function(x, y) {
  return x + y;
}

console.log(add(10, 20));	// 30

interface IsAdult {
  (age: number): boolean;
}

const a: IsAdult = (age) => {
  return age > 19;
}

console.log(a(10));	// false

 

 

ⓒ 클래스 Interface

 

interface Car {
  color: string;
  wheels: number;
  start(): void;
}

class Benz implements Car {
  color;
  wheels = 4;

  constructor(c: string) {
    this.color = c;
  }

  start() {
    console.log("go!");   
  }
}

const b = new Benz("black");
console.log(b);
b.start();

/*
Benz { wheels: 4, color: 'black' }
go!
*/

 

 

 

 

 

 

 

 

Typescript는 2021년 프로그래밍 언어 랭킹에서 8위를 차지했다

 

1 JavaScript
2 Python
3 Java
4 PHP
5 C#
5 C++
5 CSS
8 TypeScript
9 Ruby
10 C
11 Swift
12 R
13 Objective-C
14 Shell
14 Scala
16 Go
17 PowerShell
18 Kotlin
19 Rust
19 Perl

 

 

 

https://redmonk.com/sogrady/2021/03/01/language-rankings-1-21/

 

The RedMonk Programming Language Rankings: January 2021

This iteration of the RedMonk Programming Language Rankings is brought to you by MongoDB. From the edge to the cloud, MongoDB enables you to work with data as code – in any language – so you can build and ship applications faster. If you are a Python,

redmonk.com

 

 

 

 

https://www.typescriptlang.org/

 

JavaScript With Syntax For Types.

TypeScript extends JavaScript by adding types to the language. TypeScript speeds up your development experience by catching errors and providing fixes before you even run your code.

www.typescriptlang.org

 

 

 

 

 

반응형

'TypeScript' 카테고리의 다른 글

[#. Storybook] React+Typescript+Storybook 시작하기  (0) 2021.12.13