TypeScript
타입스크립트(TypeScript)는 자바스크립트의 슈퍼셋인 오픈소스 프로그래밍 언어이다. 마이크로소프트에서 개발, 유지하고 있으며 엄격한 문법을 지원한다. C#의 리드 아키텍트이자 델파이, 터보 파스칼의 창시자인 Anders Hejlsberg가 개발에 참여한다. 클라이언트 사이드와 서버 사이드를 위한 개발에 사용할 수 있다.
타입스크립트는 자바스크립트 엔진을 사용하면서 커다란 애플리케이션을 개발할 수 있게 설계된 언어이다. 자바스크립트의 슈퍼셋이기 때문에 자바스크립트로 작성된 프로그램이 타입스크립트 프로그램으로도 동작한다.
타입스크립트에서 자신이 원하는 타입을 정의하고 프로그래밍을 하면 자바스크립트로 컴파일되어 실행할 수 있다.
타입스크립트는 모든 운영 체제, 모든 브라우저, 모든 호스트에서 사용 가능한 오픈 소스이다.
Categories
- CodingGuidelines:TypeScript - TypeScript 스타일 가이드.
- TypeScript:Libraries
- TypeScript:BasicTypes
- TypeScript:Config - tsconfig.json 파일 옵션 및 설정방법 등
- TypeScript:Decorators
- TypeScript:asserts - typescript 에서 assert 사용 방법. 이 방법으로 IntelliJ계열 IDE의 타입 힌트를 제약할 수 있다.
- TypeScript:NullishCoalescing -
??
연산자. - TypeScript:Interfaces
- TypeScript:Mixins
- TypeScript:AngleBracket -
<
와>
. TypeScript에서 Type Assertion 으로 사용된다. - TypeScript:TypeOnlyImportAndExport -
import type {} from '...';
orexport type
- TypeScript:TypeDeclarations -
*.d.ts
- TypeScript:Publishing - 배포 방법.
- TypeScript:lib:es5
- TypeScript:TripleSlash - 파일 상단의
///
로 시작하는 주석. - TypeScript:Babel - babel과 함께 사용하는 방법.
- TypeScript:LibraryStructures - 라이브러리 구조화 방법.
- TypeScript:keyof
- TypeScript:never
- TypeScript:UtilityTypes
-
Awaited
<Type> -
Partial
<Type> -
Required
<Type> -
Readonly
<Type> -
Record<Keys, Type>
-
Pick<Type, Keys>
-
Omit<Type, Keys>
-
Exclude<UnionType, ExcludedMembers>
-
Extract<Type, Union>
-
NonNullable
<Type> -
Parameters
<Type> -
ConstructorParameters
<Type> -
ReturnType
<Type> -
InstanceType
<Type> -
ThisParameterType
<Type> -
OmitThisParameter
<Type> -
ThisType
<Type> -
Intrinsic String Manipulation Types
-
Uppercase
<StringType> -
Lowercase
<StringType> -
Capitalize
<StringType> -
Uncapitalize
<StringType>
-
.jsx
, .tsx
files Projects
- Excalidraw - 오픈소스 가상 칠판 협업도구
- Supabase - 오픈소스 Firebase 대체제
- Appwrite - 프론트엔드/모바일 개발자를 위한 오픈소스 백엔드 PaaS
- n8n.io - 오픈소스 워크플로우 자동화 엔진 ( Zapier 대체제 )
- Appsmith - 업무용 도구를 쉽게 만드는 Low-Code 오픈소스
- Budibase - 사내용 도구 개발을 위한 오픈소스 Low-Code 플랫폼
- Hoppscotch - API 리퀘스트 빌더
- Linen - 오픈소스 슬랙/디스코드 대체제
- Medusa - 헤드리스 이커머스 엔진, 오픈소스 Shopify 대체제
- Cal.com - https://github.com/calcom/cal.com
- Directus - https://github.com/directus/directus
- Hasura - https://github.com/hasura/graphql-engine
- Nest.js - https://github.com/nestjs/nest
- Civet - TypeScript를 더 빠르게 코딩하기 (TypeScript를 위한 CoffeScript)
- Jazz - Local-Fist 앱을 위한 프레임워크
Type Export
- tsup
- vite-plugin-dts (vite plugin)
- rollup-plugin-typescript2 (vite plugin)
Validation
- Standard Schema - TypeScript Validation을 위한 공통 인터페이스
Generate Declaration File
-
--declaration
,-d
- Generate
.d.ts
files from TypeScript and JavaScript files in your project.
-
--declarationMap
- Create sourcemaps for
d.ts
files.
-
--emitDeclarationOnly
- Only output
d.ts
files and not JavaScript files.
NonNullAssertion
또한, 데코레이터에 정의된 모든 멤버 변수에 붙어있는 !
가 NonNullAssertion 오퍼레이터라는 기능입니다.
!
가 붙은 속성이 Null
/Undefined
가 아님을 명시합니다.
사전(Dictionary) 타입 선언
interface IPerson {
firstName: string;
lastName: string;
}
var persons: { [id: string] : IPerson; } = {};
persons["p1"] = { firstName: "F1", lastName: "L1" };
위의 방법 보다 JavaScript:Map을 사용하면 된다.
Override toString method
class Foo {
private id: number = 23423;
public toString = () : string => {
return `Foo (id: ${this.id})`;
}
}
Type Casting
Integer parser:
Casting:
as
syntax:
const clueless: unknown = "1";
const clueNum: number = <number>clueless;
// another format
const clueNumPreferred = clueless as number;
Disable type checking
코드에 인라인 하는 주석은 다음과 같다.
또는 tsconfig.json를 다음과 같이 수정해라:
Exsits element
Enum name to string
String enum type
딕셔너리의 키 값을 참조하고 싶다면 다음과 같이 keyof
를 사용해도 된다:
export interface ChartTypeRegistry {
bar: {
chartOptions: BarControllerChartOptions;
datasetOptions: BarControllerDatasetOptions;
defaultDataPoint: number;
metaExtensions: {};
parsedDataType: BarParsedData,
scales: keyof CartesianScaleTypeRegistry;
};
line: {
chartOptions: LineControllerChartOptions;
datasetOptions: LineControllerDatasetOptions & FillerControllerDatasetOptions;
defaultDataPoint: ScatterDataPoint | number | null;
metaExtensions: {};
parsedDataType: CartesianParsedData;
scales: keyof CartesianScaleTypeRegistry;
};
// ...
}
export type ChartType = keyof ChartTypeRegistry;
Export imported interface
// export the default export of a legacy (`export =`) module
export import MessageBase = require('./message-base');
// export the default export of a modern (`export default`) module
export { default as MessageBase } from './message-base';
// when '--isolatedModules' flag is provided it requires using 'export type'.
export type { default as MessageBase } from './message-base';
// export an interface from a legacy module
import Types = require('./message-types');
export type IMessage = Types.IMessage;
// export an interface from a modern module
export { IMessage } from './message-types';
특정 파일의 전체 내용 export. index.ts 같은 파일에 유용.
대표 Export 객체로 하위 객체 접근 가능하도록 하기 (* as
를 지우는 방법)
import * as MyLib from 'my-lib';
과 같은 방식이 아닌, * as
를 지운 import MyLib from 'my-lib';
방식으로 Export 하고싶다면:
import Button from './Button.tsx';
export {type ButtonProps} from './Button.tsx';
export {Button};
export const YourUi = {
Button,
};
export default YourUi;
extends vs implements
다음과 같은 차이점 존재:
- extends 키워드는 class 선언문이나 class 표현식에서 만들고자하는 class의 하위 클래스를 생성할 때 사용한다.
- implements 키워드는 class의 interface에 만족하는지 여부를 체크할 때 사용된다.
Mixin
TypeScript:Mixins 항목 참조.
Declaration files
- Wikipedia (en) TypeScript # Declaration files
- TypeScript Support — Vue.js # Augmenting Types for Use with Plugins
- Stackoverflow - How to access Vue prototype property from typescript component
- Stackoverflow - About “*.d.ts” in TypeScript
선언 파일. *.d.ts
파일로 되어있다.
// token-service.d.ts
import Vue from 'vue'
import TokenService from '../path/to/token-service'
declare module 'vue/types/vue' {
interface Vue {
$tokenService: TokenService
}
}
answer 프로젝트에서 다음과 같이 사용했다:
import Vue from 'vue'
import { REST_API } from "./services/api";
declare module 'vue/types/vue' {
interface Vue {
$api: REST_API;
}
}
Current class and method name?
Object.getOwnPropertyNames
함수에 클래스의 프로토타입(class.prototype
)을 인자로 넘기면 된다.
class Foo {
bar() {
console.log(Object.getOwnPropertyNames(Foo.prototype)); // ["constructor", "bar"]
}
}
new Foo().bar();
이제 없애야할 나쁜 TypeScript 습관들
- 10 bad TypeScript habits to break this year
-
strict
모드를 사용하지 않는 것 - 디폴트 값을
||
로 정의 하는 것-
??
를 쓰거나, 파라미터 단위 폴백 정의할 것
-
-
any
를 타입으로 쓰는 것-
unknown
으로 교체할 것
- 타입가드 함수로 체크할 것
as any
사용하는 것 Optional
속성 - 이름만으로 설명가능한 풀 타입 네임 사용
!!
연산자 != null
TypeScript 지원
대부분의 경우, 타입 선언 패키지 이름은 항상 npm 상의 패키지 이름과 같아야 하지만, @types/
가 앞에 붙어야 합니다. 하지만 필요시 https://aka.ms/types 를 방문해 선호하는 라이브러리의 패키지를 찾으세요.
타입 관련 충돌시 점검 사항
package.json 파일의 resolutions
속성:
tsconfig.json의 컴파일러 옵션들:
{
"compilerOptions": {
"paths": {
"react": ["./node_modules/@types/react"]
},
"types": ["jest", "react", "react-dom"],
}
}
Troubleshooting
Could not find a declaration file for module 'xxxxx'
- Method 1 - To avoid the issue I just replace it by the standard
require()
:
- Method 2 - To avoid the issue I just replace these line in the tsconfig.json
:
TS2307: Cannot find module '@/xxxx' or its corresponding type declarations
다음과 같은 에러가 IDE(e.g. webstorm) 또는 tsc에서 출력될때,
직접 yarn tsc
를 돌려, 에러가 있나 확인해 보자. 일반적인 문제는 다음과 같다.
- tsconfig.json의
compilerOptions.moduleResolution
을node
로 설정. - tsconfig.json의
compilerOptions.paths
에 교체할 경로 추가. 주로'@/source'
처럼 되어있다면,"@/*": ["src/*"]
를 추가. - 위의
compilerOptions.paths
에 추가된 내용이 상대경로가 아닐 경우 (e.g."@/*": ["src/*"]
)compilerOptions.baseUrl
추가. 일반적으로"baseUrl": "."
이다. - tsconfig.json의
include
,exclude
에 포함, 비포함 경로 추가. 다음과 같이:
{
"include": ["src/**/*.ts", "src/**/*.tsx", "tests/**/*.ts", "tests/**/*.tsx"],
"exclude": ["node_modules", "dist"]
}
</syntaxhighlight>
추가: 만약 *.d.ts
파일과 같이 타입 선언을 목적으로 한 파일이 문제가 된다면 compilerOptions.skipLibCheck
를 true
로 하면 해결된다.
SVG 같은 이미지의 경우
- reactjs - typescript cannot find module when import svg file - Stack Overflow
- TS에서 svg import 안될 때
- (TS) TypeScript가 SVG 파일을 import하지 못하여 에러가 발생할 때 — 한 걸음씩
- TypeScript | 웹팩 # Importing Other Assets
TypeScript와 함께 비코드 애셋을 사용하려면 이러한 import에 대한 타입을 연기해야 합니다. 이를 위해서 프로젝트에 TypeScript에 대한 사용자 정의를 나타내는 custom.d.ts
파일이 필요합니다.
여러 순수 TypeScript Library 에서 파일 타입 자체 크게 관심 없을 경우
declare module "*.png";
declare module "*.jpg";
declare module "*.jpeg";
declare module "*.svg";
declare module "*.gif";
SVG 파일 하나 Default Export:
여기에서는 .svg
로 끝나는 import를 지정하고 모듈의 content를 any로 정의하여 SVG를 위한 새로운 모듈을 선언합니다. 타입을 문자열로 정의하여 URL이라는 것을 더 명확하게 할 수 있습니다. CSS, SCSS, JSON 등을 포함한 다른 애셋에도 동일한 개념이 적용됩니다.
React를 사용한다면:
declare module '*.svg' {
const value: React.FunctionComponent<React.SVGAttributes<SVGElement>>;
export default value;
}
TypeScript: Property 'xxx' does not exist on type 'MyComponent'
vue-class-component와 같은 라이브러리를 사용할 때, 별도의 위치에서 추가된 프로퍼티를 사용하는 방법:
:
!
를 사용하여 멤버 변수를 추가하면 된다. #NonNullAssertion 항목 참조.
Cannot import exported interface - export not found
다음과 같은 인터페이스가 있을 경우,
다음과 같이 import
할 수 있다:
이 경우 export not found 이란 경고가 출력될 수 있다. 다음과 같이 해결할 수 있다.
this 가 undefined 일 경우
다음과 같이 생성자에서 this를 사용한 콜백 메서드를 넘기면 해당 콜백에서 this
가 undefined
인 현상이 발생된다.
export default class ApiV2 {
constructor() {
this.api = AxiosLib.create();
this.api.interceptors.response.use(
this.onResponseFulfilled,
this.onResponseRejected,
);
}
async onResponseRejected(error) {
const self = this; // self is 'undefined'
}
}
이 현상을 해결하기 위해, 생성자에서 Anonymouse Lambda 를 사용하여 메서드를 호출하는 방법이 있다.
export default class ApiV2 {
constructor() {
this.api = AxiosLib.create();
this.api.interceptors.response.use(
(response) => {
return response;
},
async (error) => {
return this.onResponseRejected(error);
},
);
}
onResponseRejected(error) {
const self = this; // ok !!
}
}
추정이지만, 람다식을 사용해, this
를 캡쳐하는게 아닐까?
catch block error message
Use compiler option '--downlevelIteration' to allow iterating of iterators
Type 'Set<any>' is not an array type or a string type. Use compiler option '--downlevelIteration' to allow iterating of iterators.
Entry module "..." is using named and default exports together.
Entry module "src/tailwind/index.ts" is using named and default exports together. Consumers of your bundle will have to use `your-tailwind.default` to access the default export, which may not be what you want. Use `output.exports: "named"` to disable this warning.
집입점 모듈에 명명된 Export (export const Name = ...;
) 와 기본 Export (export default ...
) 를 함께 사용했다. export default ...
로 압축하면 된다.
See also
- JavaScript
- webpack
- DeviceScript - 마이크로소프트가 만든 소형 IoT 기기를 위한 TypeScript
Favorite site
- TypeScript의 소개와 개발 환경 구축
- 타입스크립트, 써야할까?
- TypeScript 핸드북 10 - 고급 타입
- [추천] TypeScript는 어떻게 공부해야 하나요? - ECMASCRIPT4는 왜 없을까? ... 부터 시작하는 내용이다. 설명을 잘 풀어냈음.
Webpack
Tutorials
- [추천] TypeScript-Handbook 한글 문서
- 번역 진행 상황 확인 후 추후 백업하자.
Guide
- Setup TypeScript for modern browser !
- TypeScript 에서 import 와 export 를 어떻게 처리할까?
- TypeScript - 남의 라이브러리 쓸 때 d.ts 파일이 없는 경우
- (Typescript) tsconfig.json의 lib
- [추천] (번역) 지난 3년간의 모든 자바스크립트 및 타입스크립트 기능